/*
 * Copyright 2008 alibaba Inc.
 *
 * author: qian.lei <pupa.qianl@alibaba-inc.com>
 */

if( !window.lex ){

var lex = {
	emptyFunction: function(){},abstractFunction: function(){ throw 'Unimplemented.'; },
	IS_IE: !!(window.attachEvent && !window.opera),
	IS_OPERA: !!window.opera,
	IS_GECKO: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
	IS_WEBKIT: navigator.userAgent.indexOf('AppleWebKit/') > -1,
	isString: function(v){ return typeof v == 'string'; },
	isNumber: function(v){ return typeof v == 'number'; },
	isFunction: function(v){ return typeof v == 'function'; },
	isUndefined: function(v){ return typeof v == 'undefined'; },
	isArray: function(v){ return typeof v == 'object' && v instanceof Array; },
	isArrayLike: function(v){ if( typeof v != 'object' ) return false; if( lex.isArray(v) || isFinite(v.length) ) return true; return false; },
	isBlank: function(v){ return typeof v == 'undefined' || v == null || v === ''; },
	xmlHeader: "<?xml version='1.0' encoding='utf-8'?>",
	xslHeader: "<?xml version='1.0' encoding='utf-8'?><xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'><xsl:output method='html'/><xsl:variable name='escape'>()[]{};=&#9;&#10;&#13;&#34;&#39;&#38;&#47;&#92;</xsl:variable>", //()[]{};=\t\n\r"'&/\
	fn: function(v,d){ return lex.isFunction(v) ? v : lex.isString(v) ? function(){ eval(v); } : d || lex.emptyFunction; },
	array: function(){
		var o,ret = [];
		for(var i=0,len=arguments.length;i<len;i++)
			if( !lex.isUndefined(o=arguments[i]) ){ if( lex.isArrayLike(o) ) for(var ii=0;ii<o.length;ii++) ret.push(o[ii]); else ret.push(o); }
		return ret;
	},
	mixin: function(){
		var a = lex.array(arguments);
		if( a.length < 2 ) return a[0];
		var o,ps;
		do{ o = a.shift(); }while( !o );
		for(var i=0;i<a.length;i++) if( ( ps = a[i] ) instanceof Object ) for(var k in ps) try{ o[k] = ps[k]; }catch(e){} // ignore it.
		return o;
	},
	each: function(){
		var a = lex.array.apply(null,arguments),f = a.last();
		if( a.length > 1 && lex.isFunction(f) ) for(var i=0,len=a.length-1;i<len;i++) if( f( a[i] ) === false ) return;
	},
	clone: function(o){
		if( typeof o != 'object' || o === null ) return o;
		if( lex.isArray(o) ){ var a = []; for(var i=0,l=o.length;i<l;i++) a[i] = lex.clone(o[i]); return a; }
		var b = {};
		for(var k in o) try{ b[k] = lex.clone(o[k]); }catch(e){} // ignore it.
		return b;
	}
};

lex.mixin(lex,{
	global: (function(){ var _g = this; return function(n){ return lex.isBlank(n) ? _g : _g[n]; }; })(),
	declare: function(s,d){
		var o = lex.global();
		if( s != '' ){ s = s.split('.'); for(var i=0;i<s.length;i++) o = ( o[s[i]] = o[s[i]] || {} ); }
		if( lex.isArray(d) ) for(var i=0;i<d.length;i+=2) o[d[i]] = d[i+1];
		return o;
	},
	create: (function(){
		var _ph = function(bc,nc){ function t(){}; var r = t.prototype = bc.prototype; nc.prototype = new t(); return r; }
		return function(){
			var a = lex.array(arguments);
			if( a.length == 0 ) return {};
			function nc(){ if( lex.isFunction(this.init) ) this.init.apply(this,arguments); };
			var bc = lex.isFunction(a[0]) ? a.shift() : false,bcp = bc && _ph(bc,nc),ncp = nc.prototype,ps,pv,fn;
			for(var i=0;i<a.length;i++)
			{
				ps = a[i];
				for(var pn in ps)
				{
					pv = ps[pn];
					if( bcp && lex.isFunction(pv) && lex.isFunction(fn=bcp[pn]) )
						pv = (function(pn,fn,sfn){ return function(){ var t = this.$super; this.$super = sfn; var r = fn.apply(this,arguments); this.$super = t; return r; }; })(pn,pv,fn);
					ncp[pn] = pv;
				}
			}
			ncp.constructor = nc;
			return nc;
		};
	})(),
	loadScript: function(uri,ps){
		if( document.getElementById(uri) ) return;
		var el = lex.mixin(document.createElement('script'),{defer:false,type:'text/javascript',id:uri,src:uri});
		( document.getElementsByTagName('head')[0] || document.body.parentNode.appendChild(document.createElement('head')) ).appendChild(el);
	},
	evalScript: (function(){ return lex.IS_IE ? function(js){
		var el = lex.mixin(document.createElement('script'),{defer:false,type:'text/javascript'});
		try{ el.innerHTML = js; }catch(e){ el.text = js; }
		( document.getElementsByTagName('head')[0] || document.body.parentNode.appendChild(document.createElement('head')) ).appendChild(el); }
		: function(js){ lex.global().eval(js) }; })(),
	escapeString: function(s){
		var ret = '',len = s.length;
		if( len == 0 ) return ret;
		var c;
		for(var i=0;i<len;i++)
		{
			c = s.charCodeAt(i);
			if( ( c >= 97 && c <= 122 ) || ( c >= 65 && c <= 90 ) || ( c >= 48 && c <= 57 ) || c == 32 || c == 44 || c == 46 )
				ret += s.charAt(i);
			else
				ret += '&#' + c + ';';
		}
		return ret;
	},
	json: (function(){
		var m = {'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};
		return function(o){
			switch( typeof o ){
				case 'undefined': case 'function': return;
				case 'boolean': return o ? 'true' : 'false';
				case 'number': return isFinite(o) ? String(o) : 'null';
				case 'string': return '"' + o.replace(/[\x00-\x1f\\"]/g,function(a){ var c = m[a]; if( c ) return c; c = a.charCodeAt(); return '\\u00' + Math.floor(c/16).toString(16) + (c%16).toString(16); }) + '"';
			}
			if( o === null ) return 'null';
			var sb = [];
			if( lex.isArray(o) )
			{
				for(var i=0,len=o.length;i<len;i++)
					sb.push(lex.json(o[i]) || 'null');
				return '[' + sb.join(',') + ']';
			}
			var v;
			for(var k in o)
				if( lex.isString(k) && lex.isString( v = lex.json(o[k]) ) ) sb.push(lex.json(k) + ':' + v);
			return '{' + sb.join(',') + '}';
		};
	})(),
	xml: (function(){
		var _m = {'<':'&lt;','>':'&gt;','"':'&quot;',"'":'&apos;','&':'&amp;'},_rep = function(a){ return _m[a] || ''; };
		var _fn = function(s){ return s.replace(/[<>\\"\\'\\&]/g,_rep); }
		return function(o){
			switch( typeof o ){
				case 'undefined': case 'function': return;
				case 'boolean': return o ? 'true' : 'false';
				case 'number': return isFinite(o) ? String(o) : '';
				case 'string': return _fn(o);
			}
			if( o === null ) return '';
			var sb = [];
			if( lex.isArray(o) )
			{
				for(var i=0,len=o.length;i<len;i++)
					sb.push(lex.xml(o[i]) || '<row/>');
				return '<rows>' + sb.join('') + '</rows>';
			}
			var v;
			for(var k in o)
				if( lex.isString(k) && /^[_a-zA-Z][-_0-9a-zA-Z]*$/.test(k) )
					if( lex.isString( v = lex.xml(o[k]) ) ) sb.push("<" + k + ">" + v + "</" + k + ">"); else sb.push("<"+k+"/>");
			return '<row>' + sb.join('') + '</row>';
		};
	})()
});

/*--------------------------------------------------------------------------*/
lex.mixin(Function.prototype,{
	defer: function(t){ window.setTimeout(this,( t || 0 )); },
	bind: function(){ var a = lex.array(arguments),fn = this,thiz = a.shift(); return function(){ return fn.apply(thiz,lex.array(a,lex.array(arguments))); }; }
});

lex.mixin(Array.prototype,{
	clear: function(){ this.length = 0; return this; },
	append: function(){ for(var i=0,len=arguments.length;i<len;i++) if( !lex.isUndefined(o=arguments[i]) ){ if( lex.isArrayLike(o) ) for(var ii=0;ii<o.length;ii++) this.push(o[ii]); else this.push(o); } return this; },
	first: function(){ return this[0]; },
	last: function(){ return this[this.length-1]; },
	indexOf: function(v,s){ var len = this.length; s = isNaN(s) ? 0 : ( s < 0 ? len + s : s ); for(;s<len;s++) if( this[s] === v ) return s; return -1; },
	lastIndexOf: function(v,s){ var len = this.length; s = isNaN(s) ? 0 : ( s < 0 ? len + s : s ); for(;len>s;len--) if( this[len-1] === v ) return len-1; return -1; },
	remove: function(ix){ this.splice(ix,1); },
	include: function(o){ return this.indexOf(o) != -1; }
});

lex.mixin(Number.prototype,{ toPaddedString: function(l,r){ var s = this.toString(r||10); return '0'.times(l-s.length) + s; } });

if( !Number.min ) Number.min = function(a,b){ return a < b ? a : b; };
if( !Number.max ) Number.max = function(a,b){ return a > b ? a : b; };

lex.mixin(String.prototype,{
	trim: function(){ return this.replace(/(^[\s\xa0]*)|([\s\xa0]*$)/g,''); }, //TODO like python's ctrip?
	translate: function(f,t){}, //TODO like xpath
	contains: function(s){ return ( s ? this.indexOf(s) != -1 : false ); },
	startsWith: function(s){ return ( s ? this.indexOf(s) == 0 : false ); },
	endsWith: function(s){ return ( s ? this.lastIndexOf(s) == this.length - s.length : false ); },
	times: function(c){ return c < 1 ? '' : new Array(c+1).join(this); },
	stripTags: function(){ return this.replace(/<\/?[^>]+>/gi,''); },
	format: (function(){
		var reg = /\{[_A-Za-z0-9-]+\}/g;
		return function(){
			if( this.length == 0 ) return '';
			var a = lex.array(arguments);
			return this.replace(reg,function(k){
				k = k.substring(1,k.length-1);
				var ret = ( k.match(/[0-9]+/g) ? a[parseInt(k)] : lex.Constants[k] );
				return lex.isUndefined(ret) ? '' : String(ret);
			 });
		};
	})(),
	merge: (function(){
		var reg = /\$\{([^}]*)\}/g;
		return function(o){
			if( this.length == 0 ) return '';
			return this.replace(reg,function(k){ k = k.substring(2,k.length-1); var ret = o[k]; return lex.isUndefined(ret) ? '' : String(ret); });
		};
	})()
});

lex.mixin(Date.prototype,{
	add: function(ms){ return new Date(this.getTime()+ms); },
	addSeconds: function(s){ return this.add(s*1000); },
	addMinutes: function(m){ return this.addSeconds(m*60); },
	addHours: function(h){ return this.addMinutes(h*60); },
	addDays: function(d){ return this.addHours(d*24); },
	addMonths: function(ms){
		if( ms == 0 ) return this;
		var y = this.getFullYear(),m = this.getMonth(),d = this.getDate(),tt = 0;
		if( ms > 0 )
			for(var i=0,len=Math.abs(ms);i<len;i++){ tt += Date.getDays(y,m+1); if( m == 11 ){ y++; m = 0; }else{ m++; } }
		else
			for(var i=0,len=Math.abs(ms);i<len;i++){ if( m == 0 ){ y--; m = 11; }else{ m--; } tt -= Date.getDays(y,m+1); }
		var ds = Date.getDays(y,m+1);
		if( d > ds ) tt += ( ms > 0 ? ds - d : d - ds );
		return this.addDays(tt);
	},
	addYears: function(year){ return new Date(this.getFullYear() + year,this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds()); },
	ym: function(){ return this.getFullYear().toPaddedString(2) + '-' + (this.getMonth() + 1).toPaddedString(2); },
	ymd: function(){ return this.ym() + '-' + this.getDate().toPaddedString(2); },
	hms: function(){ return this.getHours().toPaddedString(2) + ':' + this.getMinutes().toPaddedString(2) + ':' + this.getSeconds().toPaddedString(2); },
	ymdhms: function(){ return this.ymd() + ' ' + this.hms(); }
});

Date.getDays = function(year,month){
	switch( month ){
		case 1:case 3:case 5:case 7:case 8:case 10:case 12: return 31;
		case 4:case 6:case 9:case 11: return 30;
		case 2: return ( year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 ) ) ? 29 : 28;
		default: throw 'illegal month:' + month;
	}
};

/*--------------------------------------------------------------------------*/
(function(){
var _fm = false;
var _timeout = 20 * 1000,_interval = 50;
var _id = 0,_rm = {};
var _success = function(xhr){},_failure = function(ex){ ex.show(); };
var _errors = {0:'ERR_TIMEOUT',400:'ERR_BADREQUEST',401:'ERR_UNAUTHORIZED',403:'ERR_FORBIDDEN',404:'ERR_NOTFOUND'};
var _clear = function(id){
	var t = _rm[id];
	window.clearInterval(t[0]);
	window.clearTimeout(t[1]);
	window.setTimeout(function(){ lex.console.hide(); if( t[2] && t[2].setDisable ) t[2].setDisable(false); delete t; },200);
	delete _rm[id];
};
var _return = function(xhr,uri,ps,cb,ab){
	var st = ab ? 0 : xhr.status,async = !!cb,ex = false;
	if( st >= 200 && st < 300 )
	{
		if( xhr.getResponseHeader("lex-rt") == 'error' ) // error message like {name:'java.sql.SQception',message:'insert error',trace:'...'}
		{
			var fb = eval('('+xhr.responseText+')');
			ex = new lex.Exception(fb.name,fb.message,fb.trace);
		}
	}
	else
	{
		var err = _errors[st];
		if( !err ) // status code not definition.
			if( st >= 300 || st < 400 ) err = 'ERR_REDIRECT'; else if( st >= 500 ) err = 'ERR_SERVERERROR'; else err = 'ERR_UNKNOWN';
		ex = new lex.Exception(err,('{' + err + '}').format(),'url = {0}\nparam = {1}\n'.format(uri,ps));
	}
	if( !async ){ if( ex ) lex.throwException(ex); return xhr; }
	if( ex ) // has error.
		( typeof cb == 'object' ? ( cb['onFailure'] || _failure ) : _failure )(ex);
	else
		( lex.isFunction(cb) ? cb : typeof cb == 'object' ? ( cb['onSuccess'] || _success ) : _success )(xhr);
};
var _qs = function(ps){
	var a = [],v;
	for(var k in ps)
	{
		v = ps[k];
		if( lex.isFunction(v) ) continue;
		k = encodeURIComponent(String(k));
		a.push(k + '=' + ( lex.isBlank(v) ? '' : lex.isString(v) ? encodeURIComponent(String(v)) : String(v) ));
	}
	return a.join('&');
};
lex.mixin(lex,{
	invoke: function(uri,ps,cb){
		if( arguments.length == 0 ) throw 'lex.invoke():Illegal argument number.';
		lex.isString(ps) || ( ps = _qs(ps) );
		ps += ( ps.length > 0 ? '&' : '' ) + 't=' + String(Math.random());
		var id = _id++,async = !!cb,xhr = lex.getTransport();
		if( async )
		{
			lex.console.show('{MSG_LOADING}'.format());
			var e = window.event && ( window.event.srcElement || window.event.target );
			if( e && e.tagName )
			{
				var tn = e.tagName.toLowerCase();
				if( tn == 'button' || tn == 'input' || tn == 'a' ) lex.$(e).setDisable(true);
			}
			else
			{
				e = false;
			}
			_rm[id] = [window.setInterval(function(){ if( xhr && xhr.readyState == 4 ){ _clear(id); _return(xhr,uri,ps,cb); } },_interval),
				window.setTimeout(function(){ if( xhr && xhr.readyState != 4 ){ xhr.abort(); _clear(id); _return(xhr,uri,ps,cb,true); } },_timeout),e];
		}
		xhr.open('POST',uri,async);
		xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		xhr.setRequestHeader('lex-invoke','true');
		if( lex.traceid ) xhr.setRequestHeader('lex-traceid',lex.traceid);
		xhr.send(ps);
		if( !async ) return _return(xhr,uri,ps);
	},
	forward: function(u,ps,op){
		if( arguments.length == 0 ) throw 'lex.forward():Illegal argument number';
		var tg = '_self',md = 'POST';
		if( lex.isString(op) )
		{
			tg = op;
		}
		else if( op )
		{
			if( op.target ) tg = op.target;
			if( op.method ) md = op.method;
		}
		ps = lex.mixin(ps,{'t':Math.random()});
		if( _fm ){ while( _fm.elements.length > 0 ) _fm.removeChild(_fm.elements[0]); }
		else
		{
			_fm = document.createElement('form');
			lex.mixin(_fm.style,{display:'none',width:'0',height:'0'});
			document.body.appendChild(_fm);
		}
		for(var k in ps) _fm.appendChild(lex.mixin(document.createElement('input'),{type:'hidden',name:k,value:ps[k]}));
		lex.mixin(_fm,{action:u,method:md,target:tg}).submit();
	}
},
lex.IS_IE ?
(function(){
	var _xslt = function(d,ps){
		ps || ( ps = true );
		var p = this.template.createProcessor();
		for(var k in ps) p.addParameter(k,ps[k]);
		p.input = d;
		p.transform();
		return p.output;
	};
	return {
		getTransport: function(){ try{ return new ActiveXObject('Msxml2.XMLHTTP'); }catch(e){ return new ActiveXObject('Microsoft.XMLHTTP'); } },
		createDocument: function(str){
			var d; try{ d = new ActiveXObject('Msxml2.DOMDocument'); }catch(e){ d = new ActiveXObject('Microsoft.XMLDOM'); }
			d.async = false;
			d.loadXML(str);
			return d;
		},
		createTemplate: function(xsl){
			var d = new ActiveXObject('Msxml2.FreeThreadedDOMDocument'),t = new ActiveXObject('Msxml2.XSLTemplate');
			d.loadXML(xsl);
			t.stylesheet = d;
			return {template: t,transform: _xslt};
		}
	};
})() :
(function(){
	var _xslt = function(d,ps){
		ps || ( ps = true );
		this.processor.clearParameters();
		for(var k in ps) this.processor.setParameter('',k,ps[k]);
		return (new XMLSerializer()).serializeToString(this.processor.transformToFragment(d,document));
	};
	var _ajaxslt = function(d,ps){ return xsltProcess(d,this.xsl,ps); };
	return {
		getTransport: function(){ return new XMLHttpRequest(); },
		createDocument: function(str){ return ( DOMParser && XSLTProcessor ? (new DOMParser()).parseFromString(str,'text/xml') : xmlParse(str) ); },
		createTemplate: (function(){
			if( XSLTProcessor )
				return function(xsl){ var d = lex.createDocument(xsl),p = new XSLTProcessor(); p.importStylesheet(d); return {processor: p,transform: _xslt}; };
			return function(xsl){ var d = lex.createDocument(xsl); return {xsl: d,transform: _ajaxslt}; };
		})()
	};
})()
);
var _result = function(xhr){
	var t = xhr.getResponseHeader("lex-rt"),r;
	if( t == 'json' ){ r = eval('('+xhr.responseText+')'); }
	else if( t == 'xml' ){ r = xhr.getResponseHeader('content-type').contains('text/xml') ? xhr.responseXML : lex.createDocument(xhr.responseText); }
	else if( t == 'feedback' )
	{
		var fb = (eval('('+xhr.responseText+')')),msg = [];
		if( lex.isArray(fb.message) && fb.message.length > 0 )
		{
			msg.push('Message:');
			msg.push('<ol>');
			for(var i=0,len=fb.message.length;i<len;i++)
				msg.push('<li>' + fb.message[i] + '</li>');
			msg.push('</ol>');
		}
		if( lex.isArray(fb.error) && fb.error.length > 0 )
		{
			msg.push('Error:');
			msg.push('<ol>');
			for(var i=0,len=fb.error.length;i<len;i++)
				msg.push('<li>' + fb.error[i] + '</li>');
			msg.push('</ol>');
		}
		if( fb.level == 'error' ) lex.error(msg.join('')); else lex.alert(msg.join(''));
		r = fb;
	}
	else{ r = xhr.responseText; }
	delete xhr;
	return r;
};
var _rpc = lex.create({
	init: function(url){ this._url = url; },
	__invoke: function(id,ps,cb){
		var a = lex.json(ps);
		if( cb )
		{
			var su = lex.emptyFunction,fa = false;
			if( lex.isString(cb) ){ su = function(){ eval(cb); }; }
			else if( lex.isFunction(cb) ){ su = cb; }
			else if( typeof cb == 'object' ){ su = lex.fn(cb['onSuccess']); fa = lex.fn(cb['onFailure'],false); }
			lex.invoke(this._url,{"$rpc.id":id,"$rpc.args":a},{'onSuccess': function(xhr){ su(_result(xhr)); },'onFailure': fa});
		}
		else{ return _result(lex.invoke(this._url,{"$rpc.id":id,"$rpc.args":a})); }
	}
});
lex.createRPC = function(url){ return new _rpc(url); };
})();

/*--------------------------------------------------------------------------*/
//event
(function(){
var M = lex,_ex = false;

if( lex.IS_GECKO ){
	var fn = function(){ var f = fn.caller; do{ if( f.arguments[0] instanceof Event ) return f.arguments[0]; }while( ( f = f.caller ) != null ); return null; };
	window.constructor.prototype.__defineGetter__('event',function(){ return fn(); });
}

lex.mixin(M,{
	pointer: function(){ var e = window.event; return e ? {x:e.pageX || ( e.clientX + ( document.documentElement || document.body ).scrollLeft ),y:e.pageY || ( e.clientY + ( document.documentElement || document.body ).scrollTop )} : {x:0,y:0}; },
	stop: function(){ var e = window.event; if( e ){ if( e.preventDefault ){ e.preventDefault(); e.stopPropagation(); e.stopped = true; }else{ e.returnValue = false; e.cancelBubble = true; } } },
	onLoad: function(h){ if( window.addEventListener ) window.addEventListener('load',h,false); else if( window.attachEvent ) window.attachEvent('onload',h); },
	onUnload: function(h){ if( window.addEventListener ) window.addEventListener('unload',h,false); else if( window.attachEvent ) window.attachEvent('onunload',h); },
	onResize: function(h){ if( window.addEventListener ) window.addEventListener('resize',h,false); else if( window.attachEvent ) window.attachEvent('onresize',h); },
	onScroll: function(h){ if( window.addEventListener ) window.addEventListener('scroll',h,false); else if( window.attachEvent ) window.attachEvent('onscroll',h); },
	throwException: function(ex,m){ _ex = ex; throw m || ""; },
	currentException: function(){ return _ex; }
});

window.onerror = function(msg,url,no){ if( _ex ){ _ex.show(); _ex = false; }else{ lex.alert("[line "+no+"] "+msg); } return true; };

M.Exception = lex.create({
	init: function(n,m,t){ this.name = n; this.message = m; this.trace = t; },
	getName: function(){ return this.name; },
	getMessage: function(){ return this.message; },
	getTrace: function(){ return this.trace; },
	show: function(){ lex.error(this); }
});

M.Errors = lex.create({
	init: function(){ this._es = []; this._fes = []; },
	hasErrors : function(){ return this._es.length > 0 || this._fes.length > 0; },
	addError : function(msg){ this._es.push(msg); },
	addFieldError : function(fn,msg){ this._fes.push({fieldName:fn,message:msg}); },
	getErrors : function(){ return this._es; },
	getFieldErrors : function(){ return this._fes; },
	show: function(){
		var h = [];
		for(var i=0,len=this._es.length;i<len;i++) h.push('<li>' + this._es + '</li>');
		for(var i=0,len=this._fes.length;i<len;i++) h.push('<li>' + this._fes[i].message + '</li>');
		lex.alert(h.join(''));
	}
});
})();

/*--------------------------------------------------------------------------*/
//observable
(function(){
var M = lex.declare('lex.util');

M.Observable = lex.create({
	addListener: function(n,h){ ( ( this._hs || ( this._hs = {} ) )[n] || ( this._hs[n] = [] ) ).push(h); },
	removeListener: function(n,h){ if( h && h.call ){ var ls = ( this._hs || ( this._hs = {} ) )[n]; if( ls ){ var ix = ls.indexOf(h); if( ix != -1 ) ls.remove(ix); } }else{ if( this._hs ) delete this._hs[n]; } },
	getListeners: function(n){
		var ls = [],mn = 'on' + n.substring(0,1).toUpperCase() + n.substring(1),fn = this[mn];
		if( lex.isFunction(fn) ) ls.push(fn);
		if( lex.isString(this.name) && lex.isFunction( fn = lex.global(this.name + '_' + mn) ) ) ls.push(fn);
		return ls.append(( this._hs || ( this._hs = {} ) )[n]);
	},
	fireEvent: function(){ //event name[,arg0...argx]
		if( arguments.length == 0 ) throw 'fireEvent:illegal argument number.';
		var a = lex.array(arguments),n = a.shift();
		if( !lex.isString(n) || n === '' ) throw 'fireEvent:illegal argument, event name must be string.';
		var ls = this.getListeners(n);
		for(var i=0,l=ls.length;i<l;i++) lex.isFunction(ls[i]) && ls[i].apply(this,a);
	}
});
M.Observable.prototype.on = M.Observable.prototype.addListener;
M.Observable.prototype.un = M.Observable.prototype.removeListener;
M.Observable.prototype.fire = M.Observable.prototype.fireEvent;

if( lex.IS_IE ){
	var _ts = { 'table': ['<table>','</table>',1],'tbody': ['<table><tbody>','</tbody></table>',2],'tr': ['<table><tbody><tr>','</tr></tbody></table>',3],
		'td': ['<table><tbody><tr><td>','</td></tr></tbody></table>',4],'select': ['<select>','</select>',1]
	};
	var _tn = (function(){
		var d = false;
		return function(h,t){
			( d || ( d = document.createElement('div') ) ).innerHTML = t[0] + h + t[1];
			var e = d;
			for(var i=0;i<t[2];i++) e = e.firstChild;
			return e.firstChild;
		};
	})();
	lex.mixin(M,{
		insertBefore: function(e,h){ var t = _ts[e.tagName.toLowerCase()]; if( t ) e.parentNode.insertBefore(_tn(h,t),e); else e.insertAdjacentHTML('BeforeBegin',h); },
		insertAfter: function(e,h){ var t = _ts[e.tagName.toLowerCase()]; if( t ) e.parentNode.insertBefore(_tn(h,t),e.nextSibling); else e.insertAdjacentHTML('AfterEnd',h); },
		insertFirst: function(e,h){ var t = _ts[e.tagName.toLowerCase()]; if( t ) e.insertBefore(_tn(h,t),e.firstChild); else e.insertAdjacentHTML('AfterBegin',h); },
		insertLast: function(e,h){ var t = _ts[e.tagName.toLowerCase()]; if( t ) e.insertBefore(_tn(h,t),null); else e.insertAdjacentHTML('BeforeEnd',h); }
	});
}
else
{
	lex.mixin(M,{
		insertBefore: function(e,h){ var r = e.ownerDocument.createRange(); r.setStartBefore(e); e.parentNode.insertBefore(r.createContextualFragment(h),e); },
		insertAfter: function(e,h){ var r = e.ownerDocument.createRange(); r.setStartAfter(e); e.parentNode.insertBefore(r.createContextualFragment(h),e.nextSibling); },
		insertFirst: function(e,h){ if( e.firstChild ){ var r = e.ownerDocument.createRange(); r.setStartBefore(e.firstChild); e.insertBefore(r.createContextualFragment(h),e.firstChild); } else{ e.innerHTML = h; } },
		insertLast: function(e,h){ if( e.lastChild ){ var r = e.ownerDocument.createRange(); r.setStartAfter(e.lastChild); e.appendChild(r.createContextualFragment(h)); } else{ e.innerHTML = h; } }
	});
}

})();

/*--------------------------------------------------------------------------*/
//debug
(function(){
var _ld = false,_rd = false,_dd = false;

var M = lex.declare('lex.util'),_le = { OFF: 0,FATAL: 0,ERROR: 3,WARN: 4,INFO: 6,DEBUG: 7,ALL: 99 };
M.Logger = lex.create(M.Observable,{
	init: function(n,l){ this.name = n; this._level = l || _le.INFO; this._logs = []; },
	fatal: function(m,e){ this._log(_le.FATAL,m,e); },
	error: function(m,e){ this._log(_le.ERROR,m,e); },
	warn: function(m,e){ this._log(_le.WARN,m,e); },
	info: function(m){ this._log(_le.INFO,m); },
	debug: function(m){ this._log(_le.DEBUG,m); },
	_log: function(l,m,e){
		if( l <= this._level )
		{
			var log = {time:(new Date()).hms(),level:l,message:m,error:e};
			this._logs.push(log);
			if( _dd )
				lex.util.insertLast(_dd.lastChild,'<div>'+lex.json(log)+'</div>');
		}
	}
});

lex.onLoad(function(){
	if( lex.stage && lex.stage != 'PRODUCTION' )
	{
		var b = document.body;
		_dd = lex.$(document.createElement('div'));
		_dd.id = '_wgdd';_dd.className = 'lex-debug';
		lex.mixin(_dd.style,{filter:'alpha(opacity=95)',opacity:0.95,position:'absolute',zIndex:1000,display:'none',width:'200px',height:'300px'});
		_dd.update("<div style='padding:2px'>Debug Console</div><div style='margin:0 4px;margin:auto;background:white;overflow:auto;width:180px;height:270px;text-align:left'></div>");
		b.appendChild(_dd);
		var h = "<a class='fly-link' href='javascript:void(0);' onclick=\"lex.alert('lex3 (version:{0}; stage:{1};)\\nServer Info (ip={2})');\">About</a>&nbsp;<b>|</b>&nbsp;".format(lex.version,lex.stage,lex.ip);
		if( lex.traceid )
			h += "<a class='fly-link' href='javascript:void(0);' onclick=\"lex.invoke('.trace.do',{action:'stop'},function(){ window.location.reload(); });\" title='Stop trace'>Stop trace</a>&nbsp;<b>|</b>&nbsp;" + "<a class='fly-link' target='_blank' href='.trace.do?action=view&tid={0}' title='Show trace info. (trace id:{0})'>Show trace</a>".format(lex.traceid);
		else
			h += "<a class='fly-link' href='javascript:void(0);' onclick=\"lex.invoke('.trace.do',{action:'start'},function(){ window.location.reload(); });\" title='Start trace'>Start trace</a>";
//		h += "&nbsp;<b>|</b>&nbsp;<a class='fly-link' href='javascript:void(0);' onclick=\"this.innerHTML=(lex.$('_wgdd').toggle().visible()?'Hide':'Show')+' Debug';\">Show Debug</a>";
		_rd = lex.$(document.createElement('div'));
		lex.mixin(_rd.style,{filter:'alpha(opacity=40)',opacity:0.4,position:'absolute',zIndex:1000,textAlign:'right',top:0,left:-10000,width:'400px',height:'15px'});
		_rd.update(h);
		b.appendChild(_rd);
		var fn = function(){
			lex.mixin(_rd.style,{top:b.scrollTop + 'px',left:( b.clientWidth + b.scrollLeft - 400 - 10 ) + 'px'});
			lex.mixin(_dd.style,{top:( b.scrollTop + 16 ) + 'px',left:( b.clientWidth + b.scrollLeft - 200 ) +'px'});
		};
		lex.onScroll(function(){ fn.defer(100); });
		lex.onResize(function(){ fn.defer(100); });
		fn.defer(100);
	}
});

lex.console = {
	show: function(msg){
		var b = document.body;
		if( !_ld )
		{
			_ld = lex.mixin(lex.$(document.createElement('div')),{className:'lex-console'});
			lex.mixin(_ld.style,{position:'absolute',zIndex:2000,top:0,left:-10000,width:200,height:20,visibility:'hidden'});
			_ld.update("<div class='loading'>&nbsp;</div><div class='fly-text'>&nbsp;</div>");
			b.appendChild(_ld);
			var fn = function(){ if( _ld && _ld.visible() ) lex.mixin(_ld.style,{top:b.scrollTop}); };
			lex.onScroll(function(){ fn.defer(100); });
		}
		var e = _ld.lastChild;
		if( e ) e.innerHTML = msg;
		lex.mixin(_ld.style,{top:b.scrollTop,left:0,visibility:'visible'});
	},
	hide: function(){ if( _ld ) lex.mixin(_ld.style,{left:-10000,visibility:'hidden'}); }
};

})();

/*--------------------------------------------------------------------------*/
//model
(function(){
var M = lex.declare('lex');
var _cmp = function(r1,r2,pn){ if( r1 == r2 ) return 0; if( !r2 || !r2[pn] ) return 1; if( !r1 || !r1[pn] ) return -1; return r1[pn] - r2[pn]; };
var _sort = function(rs,s){
	var ss = s.split(','),ps = [],as = [];
	for(var i=0;i<ss.length;i++)
	{
		var p = ss[i].trim(),ix = p.lastIndexOf(" ");
		if( ix == -1 ){ as.push(true); ps.push(p); }
		else
		{
			var a = p.substring(ix).toLowerCase();
			if( a == "asc" ) as.push(true); else if( a == "desc" ) as.push(false); else continue;
			ps.push(p.substring(0,ix).trim());
		}
	}
	rs.sort(function(r1,r2){
		if( r1 == r2 ) return 0;
		for(var i=0;i<ps.length;i++){ var t = _cmp(r1,r2,ps[i]); if( t != 0 ) return as[i] ? t : -(t); }
		return 0;
	});
};

M.Model = lex.create(lex.util.Observable,{
	init: function(rs){ this._rs = rs || []; },
	getRow: function(i){ return this._rs[i||0]; },setRow: function(i,r){ this._rs[i] = r; },
	addRow: function(r){ this._rs.push(r||{}); },removeRow: function(i){ this._rs.remove(i); },
	getRowCount: function(){ return this._rs.length; },
	getRows: function(ps){
		if( !ps ) return this._rs;
		var rs = [],r,t;
		for(var i=0,len=this._rs.length;i<len;i++)
		{
			t = true;
			r = this._rs[i];
			for(var k in ps) if( lex.isString(k) && !( t = ( r[k] == ps[k] ) ) ) break;
			if( t ) rs.push(r);
		}
		return rs;
	},
	setRows: function(rs){ this.load(rs); },
	clear: function(){ this.load([]); },
	load: function(rs){ this._rs = ( lex.isArray(rs) ? rs : [rs] ); this.fire('load'); },
	reload: function(cb){ this.query(false,cb); },

	query: function(ps,cb){},
	ordering: function(s){ _sort(this._rs,s); this.load(this._rs); },
	lookup: function(pn,ks){
		if( !ks ) return [];
		if( !lex.isArray(ks) ) ks = [ks]; else if( ks.length == 0 ) return [];
		var rs = [],ps = {},t;
		for(var i=0,len=ks.length;i<len;i++)
		{
			ps[pn] = ks[i];
			t = this.getRows(ps);
			rs.push(t.length == 0 ? null : t[0]);
		}
		return rs;
	},
	validate: function(r){ return true; }
});

lex.createModel = function(rs){
	if( lex.isUndefined(rs) || rs === null ) rs = []; else if( !lex.isArray(rs) ) rs = [rs];
	return new M.Model(rs);
};

lex.createOptionModel = function(r){
	var rs = [];
	for(var k in r) rs.push({name:r[k],value:k});
	return lex.createModel(rs);
};

var _rp = '__ROOT__';

M.TreeModel = lex.create(lex.util.Observable,{
	init: function(rs){ this._rs = {_rp:rs} || {}; },
	getRows: function(p){
		p || ( p = _rp );
		var rs = this._rs[p];
		if( !rs )
			this._rs[p] = rs = loadRows(p);
		return rs;
	},
	loadRows: function(p){}
});

M.CodeTreeModel = lex.create(lex.util.Observable,{
	init: function(rs){ this._map = {}; this._rs = rs; this._cp = 'code'; },
	getRows: function(p){
		var rs = this._map[p],k = p || _rp;
		if( !rs )
			this._map[k] = rs = this.loadRows(p||'');
		return rs;
	},
	loadRows: function(p){				//将code用固定的属性名称冗余一次，tree将值传到toggleNode中，以便取下层数据
		var ret = [],rs = this._rs,v;
		if( p.length == 0 )
		{
			for(var i=0,len=rs.length;i<len;i++)
			{
				if( rs[i] && lex.isString(v = rs[i][this._cp]) && v.indexOf('.') == -1 ) ret.push(rs[i]);
			}
		}
		else
		{
			for(var i=0,len=rs.length;i<len;i++)
			{
				if( rs[i] && lex.isString(v = rs[i][this._cp]) && v.startsWith(p+'.') && v.indexOf('.',p.length+1) == -1 ) ret.push(rs[i]);
			}
		}
		return ret;
	}
});

lex.createCodeRuleTreeModel = function(rs,cp,cr){ //code property name,code rule

};

lex.createSeparatorTreeModel = function(rs,cp,se){ //code property name,code rule

};

})();

/*--------------------------------------------------------------------------*/
(function(){
var M = lex;
var sr = new RegExp('(<script[^>]*>)([\\S\\s]*?)<\/script>','img');
var pt = {
	$$: function(s){ return M.$$(s,this); },
	remove: function(){ this.parentNode.removeChild(this); return this; },
	visible: function(){ return this.getStyle('display') != 'none' && this.getStyle('visibility') != 'hidden'; },toggle: function(){ if( this.visible() ) this.hide(); else this.show(); return this; },
	hide: function(){ this.setStyle('display','none'); return this; },show: function(){ this.setStyle('display',''); return this; },
	hasClass: function(c){ return lex.isString(c) && this.className && RegExp('\\b'+c.trim()+'\\b').test(this.className); },
	toggleClass: function(c){ return this.hasClass(c) ? this.removeClass(c) : this.addClass(c); },
	addClass: function(c){ if( lex.isString(c) && !this.hasClass(c) ) if( this.className ) this.className += ' ' + c.trim(); else this.className = c.trim(); return this; },
	removeClass: function(c){ if( lex.isString(c) && this.className ) this.className = this.className.replace(new RegExp('\\b'+c.trim()+'\\b','g'),''); return this; },
	getClassName: function(){ return this.className; },setClassName: function(c){ this.className = c; return this; },
	getStyle: function(n){ return this.style[n]; },
	setStyle: function(n,v){ if( arguments.length == 1 ){ lex.mixin(this.style,arguments[0]); }else{ this.style[n] = v; } return this; },
	getOffset: function(){ var e = this,x = 0,y = 0; do{ x += e.offsetLeft || 0; y += e.offsetTop || 0; }while( e = e.offsetParent ); return {x:x,y:y}; },
	getViewportOffset: function(){ var p = this.getOffset(),x = 0,y = 0; for(var n=this;n&&n!=document.body;n=n.parentNode){ x += n.scrollLeft || 0; y += n.scrollTop || 0; } return {x:p.x-x,y:p.y-y}; },
	getWidth: function(){ return this.clientWidth; },setWidth: function(v){ this.setStyle('width',lex.isNumber(v) ? String(v) + 'px' : v); return this; },
	getHeight: function(){ return this.clientHeight; },setHeight: function(v){ this.setStyle('height',lex.isNumber(v) ? String(v) + 'px' : v); return this; },
	getRange: function(){
		if( this.getBoundingClientRect ){
			var b = document.body,box = this.getBoundingClientRect();
			return {x:box.left+b.scrollLeft,y:box.top+b.scrollTop,width:box.right-box.left,height:box.bottom-box.top};
		}
		var p = this.getViewportOffset();
		p.width = this.getWidth();
		p.height = this.getHeight();
		return p;
	},
	scrollTo: function(){ var p = this.getOffset(); window.scrollTo(p.x,p.y); return this; },
	isDisable: function(){ return this.hasClass('lex-disabled') ? true : false; },
	setDisable: function(v){
		var md = this._md;
		if( v )
		{
			if( !md )
			{
				var div = document.createElement('div');
				lex.mixin(div.style,{left:-10000,visibility:'hidden',position:'absolute',zIndex:99,filter:'alpha(opacity=60)',opacity:0.6,background:'white'});
				document.body.appendChild(div);
				this._md = md = lex.$(div);
			}
			var ra = this.getRange();
			this.addClass('lex-disabled');
			lex.mixin(md.style,{left:ra.x,top:ra.y,width:ra.width,height:ra.height,visibility:'visible'});
		}
		else if( md )
		{
			this.removeClass('lex-disabled');
			lex.mixin(md.style,{left:-10000,visibility:'hidden'});
		}
	},
	update: function(h,es){
		h = ( lex.isUndefined(h) || lex.isFunction(h) || h === null ) ? '' : String(h);
		var ss = [],ts = [];
		h = h.replace(sr,es ? function(){ var g1 = arguments[1],g2 = arguments[2],m = g1.match(/\ssrc=([\'\"])(.*?)\1/i); if( m && m[2] ){ ts.push(true); ss.push(m[2]); }else if( lex.isString(g2) ){ ts.push(false); ss.push(g2); } return ''; } : '');
		this.innerHTML = h;
		if( es )
			(function(){ for(var i=0;i<ss.length;i++) if( ts[i] ) lex.loadScript(ss[i]); else lex.evalScript(ss[i]); delete ss; delete ts;}).defer();
		return this;
	},
	load: function(url,ps,cb){
		ps = lex.mixin(ps,{'$nodecorator':'true'});
		if( cb )
		{
			var su = lex.emptyFunction,fa = false;
			if( lex.isString(cb) ){ su = (function(){ eval(cb); }).bind(this); }
			else if( lex.isFunction(cb) ){ su = cb.bind(this); }
			else if( typeof cb == 'object' ){ su = lex.fn(cb['onSuccess']).bind(this); fa = lex.fn(cb['onFailure'],false); if( !fa ) fa = fa.bind(this); }
			lex.invoke(url,ps,{'onSuccess': (function(xhr){ this.update(xhr.responseText,true); su.defer(10); }).bind(this),'onFailure': fa});
		}
		else{ this.update(lex.invoke(url,ps).responseText,true); }
	},
	on: function(n,h){
		if( this.addEventListener ) this.addEventListener(n,h,false); else if( this.attachEvent ) this.attachEvent('on'+n,h);
		return this;
	},
	un: function(n,h){
		if( this.removeEventListener ) this.removeEventListener(n,h,false); else if( this.detachEvent ) this.detachEvent('on'+n,h);
		return this;
	},
	fire: function(n){
		if( this.fireEvent ){ this.fireEvent('on' + n); }
		else
		{
			var e = document.createEvent('HTMLEvents');
			e.initEvent(n,true,true);
			this.dispatchEvent(e);
		}
		return this;
	}
};
var ipt = { isDisable: function(){ return this.disabled; },setDisable: function(v){ this.disabled = v; return this; },isReadOnly: function(){ return this.readOnly; },setReadOnly: function(v){ this.readOnly = v; return this; },getValue: function(){ return this.value; },setValue: function(v){ this.value = v; return this; } };
var bpt = { isDisable: function(){ return this.disabled; },setDisable: function(v){ this.disabled = v; return this; },getLabel: function(){ return this.value; },setLabel: function(v){ this.value = v; return this; } };
var cpt = { getValue: function(){ return ( this.checked ? true : false ); },setValue: function(v){ this.checked = ( String(v).toUpperCase() == 'TRUE' ); return this; } };

M.$ = function(e){
	lex.isString(e) && ( e = document.getElementById(e) );
	if( e && !e.$$ )
	{
		lex.mixin(e,pt);
		if( e.tagName )
		{
			var tn = e.tagName.toLowerCase();
			if( tn == 'input' )
			{
				var tt = e.type.toLowerCase();
				lex.mixin(e,ipt);
				if( tt == 'button' || tt == 'reset' || tt == 'submit' ) lex.mixin(e,bpt);
				else if( tt == 'checkbox' ) lex.mixin(e,cpt);
			}
			else if( tn == 'button' ){ lex.mixin(e,bpt); }
			else if( tn == 'select' || tn == 'textarea' ){ lex.mixin(e,ipt); }
		}
	}
	return e;
};

var _em = {},_re = /^([\w$_-]+)(?:([!^$*]?=)(.*))$/;
var _ops = function(){ // =eq,!=not eq,^=startsWith,$=endsWith,*=contains
	if( arguments.length != 6 ) return '';
	var a = arguments[1],v = arguments[3];
	if( v.contains("'") ) return '';
	switch( arguments[2] ){
		case '=': return "&&e.getAttribute('" + a + "')=='" + v + "'";
		case '!=': return "&&e.getAttribute('" + a + "')!='" + v + "'";
		case '^=': return "&&String(e.getAttribute('" + a + "')).startsWith('" + v + "')";
		case '$=': return "&&String(e.getAttribute('" + a + "')).endsWith('" + v + "')";
		case '*=': return "&&String(e.getAttribute('" + a + "')).contains('" + v + "')";
		default: return '';
	}
};

function _exp(s){ // input.lex-text[id^=xxx,style*=display:none]
	var t = '*',e = 'e',ix = s.indexOf('[');
	if( ix != -1 ) //has conditions.
	{
		lex.each(s.substring(ix+1,s.length-1).split(/[,;]/g),function(s){ e += ( !s.contains('=') ? "&&e.hasAttribute('" + s + "')" : s.replace(_re,_ops) ); });
		s = s.substring(0,ix);
	}
	if( s.length > 0 )
	{
		ix = s.indexOf('.'); // split tagName and className
		if( ix == -1 ){ t = s; }else{ ix == 0 || ( t = s.substring(0,ix) ); e += "&&e.className&&/\\b" + s.substring(ix+1) + "\\b/.test(e.className)"; }
	}
	var fn = "function(ctx){var r=[],el=ctx.getElementsByTagName('" + t + "');lex.each(el,function(e){ if(" + e + ") r.push(e); });return r;}";
	eval('fn=(' + fn + ')');
	return fn;
};

M.$$ = function(s,ctx){ // tagName.className[conditions]
	s = s.trim();
	var fn = _em[s] || ( _em[s] = _exp(s) ),ret = [];
	lex.each(fn(ctx||document),function(e){ ret.push(lex.$(e)); });
	return ret;
};
})();

/*--------------------------------------------------------------------------*/
//drag
(function(){
var M = lex.declare('lex.dd'),_md = false,_cd = false,_dx,_dy;
M.dragstart = function(e){
	if( !_md )
	{
		var div = document.createElement('div');
		lex.mixin(div.style,{left:-10000,visibility:'hidden',position:'absolute',zIndex:999,filter:'alpha(opacity=60)',opacity:0.6,cursor:'move',background:'white',border:'2px dashed gray'});
		document.body.appendChild(div);
		_md = lex.$(div);
	}
	e = lex.$(e);
	var r = e.getRange(),point = lex.pointer();
	_dx = r.x - point.x; _dy = r.y - point.y;
	lex.mixin(e.style,{left:-10000,visibility:'hidden'});
	lex.mixin(_md.style,{left:r.x,top:r.y,width:r.width,height:r.height,visibility:'visible'});
	_cd = e;
	lex.stop();
};
var _dg = function(){
	if( !_cd ) return;
	var point = lex.pointer();
	lex.mixin(_md.style,{left:_dx + point.x,top:_dy + point.y});
	lex.stop();
};
var _de = function(){
	if( !_cd ) return;
	var p = _md.getViewportOffset();
	lex.mixin(_cd.style,{left:p.x,top:p.y,visibility:'visible'});
	lex.mixin(_md.style,{left:-10000,visibility:'hidden'});
	_cd = false;
	lex.stop();
};
lex.$(document).on('mousemove',_dg).on('mouseup',_de);
})();

/*--------------------------------------------------------------------------*/
//widgets.
(function(){
var M = lex.declare('lex.widgets'),X = lex.declare('lex.xul'),_wc = 0,_wm = {};

M.$ = function(id){ return _wm[id]; };

var _ms = {
	visible: function(){ var e = this._box(); return e ? e.visible() : false; },
	toggle: function(){ var e = this._box(); if( e && e.visible ) e.visible() ? e.hide() : e.show(); },
	show: function(){ var e = this._box(); e && e.show && e.show(); },
	hide: function(){ var e = this._box(); e && e.hide && e.hide(); },
	hasClass: function(c){ var e = this._box(); return e && e.hasClass ? e.hasClass(c) : false; },
	toggleClass: function(c){ var e = this._box(); e && e.toggleClass && e.toggleClass(c); },
	addClass: function(c){ var e = this._box(); e && e.addClass && e.addClass(c); },
	removeClass: function(c){ var e = this._box(); e && e.removeClass && e.removeClass(c); },
	getClassName: function(){ var e = this._box(); return e && e.getClassName ? e.getClassName() : ''; },
	setClassName: function(c){ var e = this._box(); e && e.setClassName && e.setClassName(c); },
	getStyle: function(n){ var e = this._box(); return e && e.getStyle ? e.getStyle(n) : ''; },
	setStyle: function(n,v){ var e = this._box(); e && e.setStyle && e.setStyle.apply(e,arguments); },
	getOffset: function(){ var e = this._box(); return e && e.getOffset ? e.getOffset() : null; },
	getViewportOffset: function(){ var e = this._box(); return e && e.getViewportOffset ? e.getViewportOffset() : null; },

	getWidth: function(){ var e = this._el(); return e && e.getWidth ? e.getWidth() : 0; },
	setWidth: function(v){ var e = this._el(); e && e.setWidth && e.setWidth(v); },
	getHeight: function(){ var e = this._el(); return e && e.getHeight ? e.getHeight() : 0; },
	setHeight: function(v){ var e = this._el(); e && e.setHeight && e.setHeight(v); },
	update: function(h){ var e = this._el(); e && e.update && e.update(h); },
	load: function(url,ps,cb){ var e = this._el(); e && e.load && e.load(url,ps,cb); },

	_el: function(){ return lex.$(this.id); },_box : function(){ return lex.$(this.id); }
};

M.Base = lex.create(lex.util.Observable,{ init: function(id){ id || ( id = '_wg' + ( _wc++ ) ); _wm[id] = this; this.id = id; } },_ms);

//popup
var _pc = 0,_cp = false;

M.Popup = lex.create(M.Base,{
	maxHeight: 21*8,
	init: function(){
		this.$super('_pp_' + ( _pc++ ));
		var e = lex.mixin(lex.$(document.createElement('div')),{id:this.id,className:'lex-popup'});
		lex.mixin(e.style,{left:-10000,visibility:'hidden',position:'absolute',zIndex:200});
		document.body.appendChild(e);
		e.on('click',function(){ lex.stop(); });
	},
	show: function(x,y,h){
		if( arguments.length == 0 )
		{
			var p = lex.pointer();
			x = p.x; y = p.y;
		}
		else if( arguments.length == 1 )
		{
			var ra = arguments[0];
			x = ra.x; y = ra.y; h = ra.height;
		}
		h || ( h = 0 );
		lex.stop();
		if( _cp ) _cp.hide();
		var b = document.body,e = this._el(),mh = this.maxHeight;
		e.style.visibility = 'visible';
		if( mh > 0 && e.offsetHeight > mh )
			e.style.height = mh + 'px';
		y = ( y + h + e.offsetHeight > b.clientHeight + b.scrollTop ) && ( y - e.offsetHeight > b.scrollTop ) ? y - e.offsetHeight + 1 : y + h - 1;
		lex.mixin(e.style,{left:x + 'px',top:y + 'px'});
		_cp = this;
	},
	hide: function(){ var e = this._el(); if( e ) lex.mixin(e.style,{left:-10000,visibility:'hidden'}); _cp = false; }
});

lex.$(document).on('click',function(){ if( _cp ) _cp.hide(); });

//dialog
var _dc = 0,_cu = [],_dm = {},_md = false,_alert = false,_confirm = false,_prompt = false,_error = false,_exception = false;

M.Dialog = lex.create(M.Base,{
	init: function(op){
		this.$super('_dg_' + ( _dc++ ));
		op = lex.mixin({title:'{DIALOG_DEFAULT_TITLE}'.format(),width:800},op);
		var id = this.id,d = lex.mixin(lex.$(document.createElement("div")),{id:id + '_box'});
		lex.mixin(d.style,{position:'absolute',top:0,left:-10000,width:op.width,visibility:'hidden'});
		var h = [];
		h.push("<div class='fly-dialog'><div class='rc'><div class='rcl'></div><div class='rcr'></div><div class='rcc'></div></div>");
		h.push("<div class='fly-dialog-hd' id='{0}_header'><div style='float:right'><a class='fly-link' href='javascript:void(0);' onmousedown='lex.stop();' onclick=\"lex.widgets.$('{0}').close();\">[{DIALOG_CLOSE}]</a></div><div style='text-align:center' id='{0}_title'>{1}</div><div class='fly-clear'></div></div><div class='fly-dialog-bd'><div style='overflow:auto;text-align:center' id='{0}'>&nbsp;</div></div></div>".format(id,op.title));
		d.update(h.join(''));
		//document.body.appendChild(d);
		$('body').append(d);
		this._cb = this._rv = null;
		if( op.height ) this.setHeight(op.height);
		lex.$(id+"_header").on('mousedown',function(){ lex.dd.dragstart(id+'_box'); });
	},
	getTitle: function(){ return this._title().innerHTML; },setTitle: function(v){ this._title().update(v); },
	getCallback: function(){ return this._cb },setCallback: function(v){ this._cb = v; },
	getReturnValue: function(){ return this._rv; },setReturnValue: function(v){ this._rv = v; },
	show: function(){
		_cu.push(this);
		var b = document.body,e = this._box(),zi = 100 + ( _cu.length - 1 ) * 2;
		if( !_md )
		{
			_md = document.createElement("div");
			lex.mixin(_md.style,{position:'absolute',top:0,background:'#eee',filter:'alpha(opacity=60)',opacity:0.6});
			b.appendChild(_md);
		}
		lex.mixin(_md.style,{left:0,height:Number.max(b.clientHeight,b.scrollHeight)+'px',width:Number.max(b.clientWidth,b.scrollWidth)+'px',visibility:'visible',zIndex:zi});
		var x = ( b.clientWidth - e.getWidth() ) / 2,y = Number.max(50,( document.body.clientHeight - e.getHeight() ) / 2 - 100);
		lex.mixin(e.style,{left:x + b.scrollLeft,top:y + b.scrollTop,visibility:'visible',zIndex:zi+1});
		e.focus();
	},
	hide: function(){
		while( _cu.last() === this ) _cu.pop();
		var dc = _cu.length;
		lex.mixin(this._box().style,{left:-10000,visibility:'hidden'});
		lex.mixin(_md.style,( dc == 0 ? {left:-10000,visibility:'hidden'} : {zIndex:100 + ( dc - 1 ) * 2} ));
	},
	returnValue: function(rv){ this.setReturnValue(rv); this.close(); },
	close: function(){ this.hide(); if( lex.isFunction(this._cb) ) this._cb.apply(this,[this._rv]); },
	_box: function(){ return lex.$(this.id + '_box'); },
	_title: function(){ return lex.$(this.id + '_title'); }
});

lex.declare("lex",[
	'currentDialog',function(){ return _cu.last(); },
	'createDialog',function(op){ return new M.Dialog(op); },
	'showDialog',function(url,ps,op,cb){
		var d;
		if( ps )
		{
			d = lex.createDialog(op);
			d.load(url,ps,function(){ d.show(); });
		}
		else
		{
			if( d = _dm[url] ){ d.show(); }
			else
			{
				 d = lex.createDialog(op);
				 d.load(url,ps,function(){ _dm[url] = d; d.show(); });
			}
		}
		d.setCallback(cb);
		d.setReturnValue(null);
	},
	'alert',function(msg,cb){
		var d = _alert;
		if( !d )
		{
			d = _alert = lex.createDialog({width:580});
			d.update("<div style='padding:10px 30px'><div class='fly-dialog-alert'></div><div id='{0}_msg' style='float:left;width:400px;text-align:left;padding:5px'></div><div class='fly-clear'></div></div><div style='margin-bottom:12px'><input type='button' class='fly-button' value='  {DIALOG_BUTTON_YES}  ' onclick=\"_lex_.alert_close();\"></div>".format(d.id));
		}
		lex.$(d.id + "_msg").update(lex.isString(msg) ? msg.trim().replace(/\n/g,'<br/>') : '');
		d.setCallback(cb);
		d.show();
	},
	'confirm',function(msg,cb){
		var d = _confirm;
		if( !d )
		{
			d = _confirm = lex.createDialog({width:580});
			d.update("<div style='padding:10px 30px'><div class='fly-dialog-confirm'></div><div id='{0}_msg' style='float:left;width:400px;text-align:left;padding:5px'></div><div class='fly-clear'></div></div><div style='margin-bottom:12px'><input type='button' class='fly-button' value='  {DIALOG_BUTTON_YES}  ' onclick=\"_lex_.confirm_ok();\">&nbsp;&nbsp;&nbsp;<input type='button' class='fly-button' value='  {DIALOG_BUTTON_NO}  ' onclick='_lex_.confirm_no();'></div>".format(d.id));
		}
		lex.$(d.id + "_msg").update(lex.isString(msg) ? msg.trim().replace(/\n/g,'<br/>') : '');
		d.setCallback(cb);
		d.setReturnValue(false);
		d.show();
	},
	'prompt',function(msg,def,cb){
		var d = _prompt;
		if( !d )
		{
			d = _prompt = lex.createDialog({width:580});
			d.update("<div style='padding:10px 30px'><div class='fly-dialog-prompt'></div><div style='float:left;width:400px;text-align:left;padding:5px'><div id='{0}_msg'></div><br/><input id='{0}_ipt' class='fly-input' style='float:left;width:300'></div><div class='fly-clear'></div></div><div style='margin-bottom:12px'><input type='button' class='fly-button' value='  {DIALOG_BUTTON_YES}  ' onclick=\"_lex_.prompt_ok();\">&nbsp;&nbsp;&nbsp;<input type='button' class='fly-button' value='  {DIALOG_BUTTON_NO}  ' onclick=\"_lex_.prompt_no();\"></div>".format(d.id));
		}
		def = def || '';
		lex.$(d.id + "_msg").update(lex.isString(msg) ? msg.trim().replace(/\n/g,'<br/>') : '');
		lex.$(d.id + "_ipt").value = def;
		d.setCallback(cb);
		d.setReturnValue(def);
		d.show();
	},
	'error',function(e,cb){
		var d = _error;
		if( !d )
		{
			d = _error = lex.createDialog({width:580});
			d.update("<div style='padding:10px 30px'><div class='fly-dialog-error'></div><div id='{0}_msg' style='float:left;width:400px;text-align:left;padding:5px'></div><div class='fly-clear'></div></div><div style='margin-bottom:12px'><input type='button' class='fly-button' value='  {DIALOG_DETAIL}  ' onclick=\"lex.$('{0}_trace').toggle();\">&nbsp;&nbsp;&nbsp;<input type='button' class='fly-button' value='  {DIALOG_CLOSE}  ' onclick=\"lex.widgets.$('{0}').close();\"></div><div id='{0}_trace' style='overflow:auto;text-align:left;width:560px;height:200px;border:1px solid #e0e0e0;margin:5px;white-space:nowrap'></div>".format(d.id));
		}
		var m,t = false;
		if( lex.isString(e) ){ m = e; }else{ m = e.message; t = e.trace; }
		lex.$(d.id + "_msg").update(lex.isString(m) ? m.trim().replace(/\n/g,'<br/>') : '');
		lex.$(d.id + "_trace").update(lex.isString(t) ? t.trim().replace(/\n/g,'<br/>').replace(/\t/g,'&nbsp;&nbsp;&nbsp;&nbsp;') : '').hide();
		d.setCallback(cb);
		d.show();
	}
]);

lex.declare('_lex_',[
	'alert_close',function(){ var d = _cu.last(); if( d ) d.close(); },'error_close',function(){ var d = _cu.last(); if( d ) d.close(); },
	'confirm_ok',function(){ var d = _cu.last(); if( d ) d.returnValue(true); },'confirm_no',function(){ var d = _cu.last(); if( d ) d.returnValue(false); },
	'prompt_ok',function(){ var d = _cu.last(); if( d ) d.returnValue(lex.$(d.id + "_ipt").value); },'prompt_no',function(){ var d = _cu.last(); if( d ) d.close(); }
]);

//render
M.Render = lex.create(M.Base,{
	render: function(){
		var e = this._el();
		if( e )
		{
			e.update(this.markup()||'');
			this.fire('render');
		}
	},
	markup: function(){ return this.id; }
});

//calendar
var _today = new Date(),_today_ymd = _today.ymd(),_tomorrow_ymd = _today.addDays(1).ymd();
var _parse = function(s){ if( /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/.test(s) == false ) throw "Date format error,must be yyyy-mm-dd."; var t = s.split('-'); return new Date(parseInt(t[0]),parseInt(t[1])-1,parseInt(t[2])); };
var _ns = function(ix){ if( ix > 9 ) return ''+ix; return '0'+ix; };
var _hour_ops,_minute_ops,_second_ops;
_hour_ops = (function(){ var r; for(var i=0;i<24;i++) r += "<option value='" + ( i < 10 ? '0' + i : i ) + "'>" + i + "</option>"; return r; })();
_minute_ops = _second_ops = (function(){ var r; for(var i=0;i<60;i+=5) r += "<option value='" + ( i < 10 ? '0' + i : i ) + "'>" + i + "</option>"; return r; })();

M.Calendar = lex.create(M.Render,{
	init: function(id){ this.$super(id); this._date = _today; this._sv = _today_ymd; this._changed = false; },
	getDate: function(){ return this._date; },
	setDate: function(d){ this._date = d; if( this.visible() ) this.render(); else this._changed = true; return this; },
	addYears: function(y){ this.setDate(this._date.addYears(y)); return this; },
	addMonths: function(m){ this.setDate(this._date.addMonths(m)); return this; },
	show: function(){ if( this._changed ) this.render(); else this._changed = false; this.$super(); },
	select: function(v,e){
		if( this.mode == 'dt' )
		{
			if( this._se )
				this._se.removeClass('lex-select-item-selected');
			if( e )
			{
				e = lex.$(e);
				e.addClass('lex-select-item-selected');
				this._se = e;
			}
			else
			{
				this.fire('select',v);
			}
			this._sv = v;
		}
		else
		{
			lex.isBlank(v) || this.setDate(_parse(v));
			this.fire('select',v);
		}
	},
	confirm: function(){
		var dt = this._sv || _today_ymd,eh = lex.$(this.id+"_h"),em = lex.$(this.id+"_m"),es = lex.$(this.id+"_s");
		if( eh && em && es )
			dt += ' ' + eh.value + ':' + em.value + ':' + es.value;
		if( this._se )
			this._se.removeClass('lex-select-item-selected');
		this.fire('select',dt);
	},

	markup: function(){
		var y = this._date.getFullYear(),m = this._date.getMonth()+1,tmp = "lex.widgets.$('" + this.id + "')",ymd;
		var h = ["<table cellspacing='0' cellpadding='0' border='0' width='100%' class='fly-calendar' style='padding:1px'>"];
		h.push("<tr><th colspan='3' style='padding:1;border-bottom:1px solid #f0f0f0;'>");
		h.push("<a href='javascript:void(0);' class='fly-link' onclick=\"javascript:{0}.select('');\">[{CLEAR}]</a>".format(tmp));
		if( this.mode == 'dt' )
			h.push("&nbsp;<a href='javascript:void(0);' class='fly-link' onclick=\"javascript:{0}.select((new Date()).ymdhms());\">[{NOW}]</a>".format(tmp));
		else
			h.push("&nbsp;<a href='javascript:void(0);' class='fly-link' onclick=\"javascript:{0}.select('{1}');\">[{TODAY}]</a>&nbsp;<a href='javascript:void(0);' class='fly-link' onclick=\"javascript:{0}.select('{2}');\">[{TOMORROW}]</a>".format(tmp,_today_ymd,_tomorrow_ymd));
		h.push("</th></tr>");
		h.push("<tr><th nowrap='true' align='left'><a href='javascript:void(0);' onclick=\"javascript:{0}.addYears(-1);\"><<</a>&nbsp;<a href='javascript:void(0);' onclick=\"javascript:{0}.addMonths(-1);\"><-</a></th><th nowrap='true'>{1}{YEAR}{2}{MONTH}</th><th nowrap='true' align='right'><a href='javascript:void(0);' onclick=\"javascript:{0}.addMonths(1);\">-></a>&nbsp;<a href='javascript:void(0);' onclick=\"javascript:{0}.addYears(1);\">>></a></th></tr>".format(tmp,y,m));
		h.push("<tr><td colspan='3'><table cellspacing='1' cellpadding='1' border='0' width='100%' class='fly-calendar'><tr class='header' align='center'><td>{CALENDAR_MON}</td><td>{CALENDAR_TUE}</td><td>{CALENDAR_WEB}</td><td>{CALENDAR_THU}</td><td>{CALENDAR_FRI}</td><td>{CALENDAR_SAT}</td><td>{CALENDAR_SUN}</td></tr>".format());
		var dt = new Date(y,m-1,1),tdays = Date.getDays(y,m),ldays = dt.addDays(-1).getDate(),day = -(dt.getDay() + 5),col = 0;
		for(var i=0;i<49;i++)
		{
			if( col == 0 ) h.push("<tr align='right'>");
			var cls = 'lex-select-item ' + ( col < 5 ? 'normal' : 'weekend' );
			if( day <= 0 )
			{
				ymd = ( m == 1 ? y - 1 : y ) + '-' + _ns( m == 1 ? 12 : m - 1 ) + '-' + _ns( ldays + day );
				h.push("<td style='color:#b0b0b0;' class='{0}' onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\" onclick=\"{1}.select('{2}',this);\" title='{2}'>{3}</td>".format(cls,tmp,ymd,ldays + day));
			}
			else if( day > tdays )
			{
				ymd = ( m == 12 ? y + 1 : y ) + '-' + _ns( m == 12 ? 1 : m + 1 ) + '-' + _ns( day - tdays );
				h.push("<td style='color:#b0b0b0;' class='{0}' onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\" onclick=\"{1}.select('{2}',this);\" title='{2}'>{3}</td>".format(cls,tmp,ymd,day - tdays));
			}
			else
			{
				ymd = y + '-' + _ns(m) + '-' + _ns(day);
				h.push("<td style='color:#444444;' class='{0}' onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\" onclick=\"{1}.select('{2}',this);\" title='{2}'>{3}</td>".format(cls,tmp,ymd,day));
			}
			col++; day++;
			if( col == 7 )
			{
				col = 0;
				h.push('</tr>');
			}
		}
		h.push("</table></td></tr>");
		if( this.mode == 'dt' )
		{
			h.push("<tr><td colspan='3' nowrap='true' style='padding:1;border-top:1px solid #f0f0f0;border-bottom:1px solid #f0f0f0;'><select class='fly-calendar-select' id='{1}_h'>{2}</select> {HOUR}<select class='fly-calendar-select' id='{1}_m'>{3}</select> {MINUTE}<select class='fly-calendar-select' id='{1}_s'>{4}</select> {SECOND}</td></tr>".format(tmp,this.id,_hour_ops,_minute_ops,_second_ops));
			h.push("<tr><th colspan='3' style='padding:2'><input type='button' class='fly-button' value='   {DIALOG_BUTTON_YES}  ' onclick=\"lex.widgets.$('{0}').confirm();\"/>&nbsp;&nbsp;&nbsp;&nbsp;<input type='button' class='fly-button' value='  {DIALOG_BUTTON_NO}  '/></th></tr>".format(this.id));
		}
		h.push("</table>");
		return h.join('');
	}
});

//pagingToolbar
M.PagingToolbar = lex.create(M.Render,{
	init: function(id,name,mod){ this.$super(id); this.name = name; this.model = mod; mod.on('load',this.render.bind(this)); },
	markup: function(){
		var mod = this.model,tt = mod.total;
		var h = [];
		if( tt > 0 )
		{
			var max = mod.max;
			if( max > 0 )
			{
				var tid = this.tid,skip = mod.skip,mp = Math.floor(tt / max) + ( tt % max == 0 ? 0 : 1 ),cp;
				if( mod.start == 0 )
					cp = Math.floor( ( skip + 1 ) / max) + ( ( skip + 1 ) % max == 0 ? 0 : 1 );
				else
					cp = Math.floor( skip / max ) + ( skip % max == 0 ? 0 : 1 );
				h.push("<div class='fly-text' style='float:left;padding:0 3px'>{0}/{1}{PAGINGTOOLBAR_PAGE}&nbsp;{2}{PAGINGTOOLBAR_LINE}&nbsp;</div><div style='float:left;padding:0 3px'><a tid='{3}_f' href='javascript:void(0);'".format(cp,mp,tt,tid));
				if( cp == 1 )
					h.push(" class='fly-link-disabled'");
				else
					h.push(" class='fly-link' onclick=\"lex.widgets.$('{0}').goPage(1);\"".format(this.id));
				h.push(">[{PAGINGTOOLBAR_FIRST}]</a>&nbsp;<a tid='{0}_p' href='javascript:void(0);'".format(tid));
				if( cp == 1 )
					h.push(" class='fly-link-disabled'");
				else
					h.push(" class='fly-link' onclick=\"lex.widgets.$('{0}').goPage({1});\"".format(this.id,Math.max(cp-1,1)));
				h.push(">[{PAGINGTOOLBAR_PREV}]</a>&nbsp;<a tid='{0}_n' href='javascript:void(0);'".format(tid));
				if( cp == mp )
					h.push(" class='fly-link-disabled'");
				else
					h.push(" class='fly-link' onclick=\"lex.widgets.$('{0}').goPage({1});\"".format(this.id,Math.min(cp+1,mp)));
				h.push(">[{PAGINGTOOLBAR_NEXT}]</a>&nbsp;<a tid='{0}_l' href='javascript:void(0);'".format(tid));
				if( cp == mp )
					h.push(" class='fly-link-disabled'");
				else
					h.push(" class='fly-link' onclick=\"lex.widgets.$('{0}').goPage({1});\"".format(this.id,mp));
				h.push(">[{PAGINGTOOLBAR_LAST}]</a>".format());
			}
			else
			{
				h.push("<div class='fly-text' style='float:left;padding:0 3px'>&nbsp;{0}&nbsp;{PAGINGTOOLBAR_LINE}&nbsp;</div>".format(tt));
			}
		}
		else if( tt == 0 )
		{
			h.push("<div class='fly-text' style='float:left;padding:0 3px'>{PAGINGTOOLBAR_EMPTY_RESULT}</div>".format());
		}
		else
		{
			h.push("<div class='fly-text' style='float:left;padding:0 3px'>{PAGINGTOOLBAR_LAZYLOADING}</div>".format());
		}
		if( tt >= 0 )
			h.push("&nbsp;<a tid='{0}_r' class='fly-link' href='javascript:;' onclick=\"lex.widgets.$('{1}').refresh();\">[{PAGINGTOOLBAR_REFRESH}]</a></div>".format(tid,this.id));
		h.push("<div class='fly-clear'></div>");
		return h.join("");
	},
	goPage: function(p){
		var m = this.model;
		m.skip = m.max * ( p - 1 ) + m.start;
		m.reload(true);
	},
	refresh: function(){ this.model.reload(true); }
});

/*--------------------------------------------------------------------------*/
//xul
X.create = function(bc,m1,m2){ // base class,widget methods,group methods
	var m3 = {};
	for(var k in m1) if( lex.isFunction(m1[k]) ){ eval('m3[k] = (function(){ var w = this.getWidget(); return w.' + k + '.apply(w,arguments); })'); }
	var wc = lex.create(bc,m3,m2),ic = bc.prototype._item;
	wc.prototype._item = lex.isFunction(ic) ? lex.create(ic,m1) : lex.create(m1);
	return wc;
};

X.Base = X.create(M.Base,_ms,{
	init: function(id,name){ this.$super(id); this.name = name; },
	getWidget: function(rid){
		rid = lex.isBlank(rid) ? '' : lex.isNumber(rid) ? '_' + rid : rid;
		var id = this.id + rid,e = ( this._ws || ( this._ws = {} ) )[id];
		if( !e )
			this._ws[id] = e = lex.mixin(new this._item(),{id:id,rid:rid,_group:this});
		return e;
	},
	getWidgets: function(){ return this._ws; } //TODO 没有实现，需要规范widget id.
});

X.Spacer = X.create(X.Base);

X.Vbox = X.Hbox = X.Item = X.Panel = X.create(X.Base);

_ms = { isDisable: function(){ return this._el().isDisable(); },setDisable: function(v){ this._el().setDisable(v); },getLabel: function(){ return this._el().value; },setLabel: function(v){ this._el().value = v; } };
X.Button = X.create(X.Base,_ms);

_ms = { getLabel: function(){ this._el().innerHTML; },setLabel: function(v){ this._el().update(v); } };
X.Link = X.create(X.Base,_ms);

_ms = { getSrc: function(){ return this._el().src; },setSrc: function(v){ this._el().src = v; } };
X.Image = X.create(X.Base,false,_ms);

_ms = { getText: function(){ return this._el().innerHTML; },setText: function(v){ this._el().update(v); } };
X.Text = X.create(X.Base,_ms);

_ms = {
	currentTab: function(){ return this._cu; },
	changeTab: function(ix){
		var old = this.currentTab();
		if( old == ix ) return;
		var e;
		if( lex.isNumber(old) )
		{
			if( e = lex.$(this.id + '_t' + old) ) e.removeClass('selected');
			if( e = lex.$(this.id + '_p' + old) ) e.hide();
		}
		if( e = lex.$(this.id + '_t' + ix) ){ e.show(); e.addClass('selected'); }
		if( e = lex.$(this.id + '_p' + ix) )
		{
			e.show();
			if( ( e = lex.$(e.firstChild) ) ) e.show(); // if firstChild is hiden, show it.
		}
		this._cu = ix;
		this._group.fire('tabChanged',ix);
	},
	getTabTitle: function(ix){ return lex.$(this.id + '_t' + ix).innerHTML; },
	setTabTitle: function(ix,title){ lex.$(this.id + '_t' + ix).update(title); },
	hideTab: function(ix){
		var e,curr = this.currentTab();
		if( ix == curr )
		{
			for(var i=0;true;i++)
			{
				if( i == curr ) continue;
				if( !( e = lex.$(this.id + '_t' + i) ) ) break;
				if( e.visible() )
				{
					this.changeTab(i);
					break;
				}
			}
		}
		if( e = lex.$(this.id + '_t' + ix) ) e.hide();
		if( e = lex.$(this.id + '_p' + ix) ) e.hide();
	},
	showTab: function(ix){
		var e;
		if( e = lex.$(this.id + '_t' + ix) ) e.show();
	},
	toggleTab: function(ix){
		var e = lex.$(this.id + '_t' + ix);
		if( e ){ if( e.visible() ) this.hideTab(ix); else  this.showTab(ix); }
	}
};
X.Tabset = X.create(X.Base,_ms);

//input
_ms = {
	isDisable: function(){ return this._el().isDisable(); },setDisable: function(v){ var e = this._el(); if( e ){ e.disabled = v; if( v ) e.addClass('lex-disable'); else e.removeClass('lex-disable'); } },
	isReadOnly: function(){ return this._el().readOnly; },setReadOnly: function(v){ var e = this._el(); if( e ){ e.readOnly = v; if( v ) e.addClass('lex-readonly'); else e.removeClass('lex-readonly'); } },
	getValue: function(){ return this._el().value.trim(); },setValue: function(v){ this._el().value = ( lex.isUndefined(v) || v === null ? '' : String(v) ); }
};
X.Input = X.create(X.Base,_ms);

_ms = {
	_box : function(){ return lex.$(this.id+'_box'); },
	isReadOnly: function(){ var e = lex.$(this.id + '_cb'); if( e ) return e.isDisable(); return false; },
	setReadOnly: function(val){ var e = lex.$(this.id + '_cb'); if( e ) e.setDisable(val); },
	isDisable: function(){ var e = lex.$(this.id + '_cb'); if( e ) return e.isDisable(); return false; },
	setDisable: function(val){ var e = lex.$(this.id + '_cb'); if( e ) e.setDisable(val); },
	setValue: function(v){ var e = this._el(); if( e && e.setValue ) e.setValue(v); if( e = lex.$(this.id + '_cb') ) e.checked = ( 'true' == String(v).toLowerCase() ); }
};
X.Checkbox = X.create(X.Input,_ms);

_ms = {
	_box : function(){ return lex.$(this.id+'_box'); },
	isDisable: function(){ var e = lex.$(this.id+'_op0'); return e ? e.isDisable() : false; },
	setDisable: function(v){ lex.each(lex.$$('input[id^='+this.id+'_op]'),function(e){ if( e && e.setDisable ) e.setDisable(v); }); },
	setValue: function(v){ this._group._setValue(this.id,v); }
};
_ms.isReadOnly = _ms.isDisable;
_ms.setReadOnly = _ms.setDisable;
X.Choice = X.create(X.Input,_ms,{
	onRender: function(rid){
		rid || ( rid = '' );
		var e = lex.$$('input[id^=' + this.id + rid + ',type=hidden]');
		for(var i=0,len=e.length;i<len;i++) this._setValue(e[i].id,e[i].value);
	},
	_setValue: function(id,v){
		var e = lex.$(id);
		if( e ){ e.value = v; lex.each(lex.$$('input[id^='+id+'_op]'),function(e){ e.checked = ( e.value == v ); }); }
	}
});

_ms = { _box : function(){ return lex.$(this.id+'_box'); } };
X.TriggerInput = X.create(X.Input,_ms,{
	minWidth: 50,
	trigger: function(did){
		var e = this._input(did);
		if( !e || e.hasClass('lex-readonly') || e.hasClass('lex-disable') ) return;
		if( !this._pp )
		{
			this._pp = new lex.widgets.Popup();
			this.buildPopup(this._pp);
		}
		else if( this._pp.visible() && this._did == did )
		{
			this.untrigger();
			return;
		}
		var ra = e.getRange();
		this._did = did;
		this._pp.setWidth(Number.max(ra.width+20,this.minWidth));
		this._pp.show(ra.x,ra.y,ra.height);
	},
	untrigger: function(){
		this._did = false;
		this._pp.hide();
	},
	buildPopup: lex.emptyFunction,
	_input: function(id){ return lex.$(id); }
});

_ms = {
	_se: function(){ return lex.$(this.id+'_se'); },
	setValue: function(v){ this._group._setValue(this.id,v); },
	isDisable: function(){ return this._se().isDisable(); },
	setDisable: function(v){ var e = this._se(); if( e ){ e.disabled = v; if( v ) e.addClass('lex-disable'); else e.removeClass('lex-disable'); } },
	isReadOnly: function(){ return this._se().isReadOnly(); },
	setReadOnly: function(v){ var e = this._se(); if( e ){ e.readOnly = v; if( v ) e.addClass('lex-readonly'); else e.removeClass('lex-readonly'); } }
};
X.Select = X.create(X.TriggerInput,_ms,{
	init: function(id,name){ this.$super(id,name); lex.mixin(this,{_mod:false,_vp:'value',_dp:'name',_hint:false}) },
	buildPopup: function(pp){
		var xsl = [lex.xslHeader,"<xsl:template match='/rows'><table cellspacing='1' cellpadding='2' style='width:100%;height:100%'>"];
		if( this._hint )
			xsl.push("<tr valign='middle' height='20px'><td class='fly-select-item' onclick=\"lex.$(this).removeClass('lex-select-item-over');lex.widgets.$('{0}').select(-1);\" onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\"{2}>{1}</td></tr>".format(this.id,this._hint,(this.tid?" tid='"+this.tid+"_item'":'')));
		xsl.push("<xsl:for-each select='row'><xsl:variable name='ix' select='position()-1'/><tr valign='middle' height='20px'><td class='fly-select-item'");
		xsl.push(" onclick=\"lex.$(this).removeClass('lex-select-item-over');lex.widgets.$('{0}').select({$ix});\" onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\"{2}><xsl:value-of select='{1}'/>".format(this.id,this._dp,(this.tid?" tid='"+this.tid+"_item{$ix}'":'')));
		xsl.push("</td></tr></xsl:for-each></table></xsl:template></xsl:stylesheet>");
		var t = lex.createTemplate(xsl.join(''));
		if( t )
		{
			fn = (function(){ if( this._mod ) pp.update(t.transform(lex.createDocument("<?xml version='1.0' encoding='utf-8'?>" + lex.xml(this._mod.getRows())))); }).bind(this);
			if( this._mod ) this._mod.on('load',fn);
			fn();
		}
	},
	onRender: function(rid){
		rid || ( rid = '' );
		var e = lex.$$('input[id^=' + this.id + rid + ',type=hidden]');
		for(var i=0,len=e.length;i<len;i++) this._setValue(e[i].id,e[i].value);
	},
	select: function(ix){
		this._setRef(this._did,ix == -1 ? false : this._mod.getRow(ix));
		lex.$(this._did).fire('change');
		this.untrigger();
	},
	mapping: lex.emptyFunction,
	_select: function(did,ix){ this._setRef(did,ix < 0 ? false : this._mod.getRow(ix)); },
	_setRef: function(did,ref){
		var e,v = this.view;
		if( e = lex.$(did) ) e.value = ( ref ? ref[this._vp] : '' ); // set value property
		if( e = lex.$(did+'_se') ) e.value = ( ref ? ref[this._dp] : this._hint || '' ); // set display property
		if( v )
		{
			var row,rid = did.substring(this.id.length),ix;
			if( rid.length == 0 || ( ix = rid.lastIndexOf('_') ) == -1 ) // rid is empty.
				row = v.getRow();
			else
				row = ( ix == 0 ? v.getRow(rid.substring(ix+1)) : v.getWidget(rid.substring(0,ix)).getRow(rid.substring(ix+1)) );
			if( row ) this.mapping(row,ref||{}); // do mapping
		}
	},
	_setValue: function(did,v){
		if( !did || !this._mod ) return;
		if( lex.isBlank(v) )
		{
			this._setRef(did,this._def < 0 ? false : this._mod.getRow(this._def));
		}
		else
		{
			var param = {},rows;
			param[this._vp] = v;
			rows = this._mod.getRows(param); // get row from model.
			this._setRef(did,rows.length > 0 ? rows[0] : false);
		}
	},
	_input: function(id){ return lex.$(id + '_se'); }
});

X.Lookup = X.create(X.Input,false,{
	init: function(id,name){ this.$super(id,name); lex.mixin(this,{_mod:false,_vp:'value',_dp:'name',_hint:false}) },
	onRender: function(rid){
		rid || ( rid = '' );
		var e = lex.$$('input[id^=' + this.id + rid + ',type=hidden]'),ks = [],vs;
		for(var i=0,len=e.length;i<len;i++) ks.push(e[i].value);
		vs = this._mod.lookup(this._vp,ks);
		for(var i=0,len=e.length;i<len;i++) this._setRef(e[i].id,vs[i],ks[i]);
	},
	mapping: lex.emptyFunction,
	_setRef: function(did,ref,val){
		var e = lex.$(did+'_d'),v = this.view;
		if( e ) e.update( ref ? ref[this._dp] : this._hint || ( lex.isUndefined(val) ? '' : val ) ); // set display property.
		if( v )
		{
			var row,rid = did.substring(this.id.length),ix;
			if( rid.length == 0 || ( ix = rid.lastIndexOf('_') ) == -1 ) // rid is empty.
				row = v.getRow();
			else
				row = ( ix == 0 ? v.getRow(rid.substring(ix+1)) : v.getWidget(rid.substring(0,ix)).getRow(rid.substring(ix+1)) );
			if( row ) this.mapping(row,ref||{});
		}
	}
});

X.DateInput = X.create(X.TriggerInput,false,{
	minWidth: 180,
	buildPopup: function(pp){
		pp.maxHeight = -1;
		var cal = new M.Calendar(pp.id);
		cal.mode = this.mode;
		cal.on('select',(function(v){ lex.$(this._did).setValue(v).fire('change'); this.untrigger(); }).bind(this));
		cal.render();
	}
});

X.TimeInput = X.create(X.TriggerInput,false,{
	minWidth: 60,
	buildPopup: function(pp){
		var tmp = lex.createTemplate(lex.xslHeader + "<xsl:template match='/rows'><table cellspacing='1' cellpadding='2' style='width:100%;height:100%'><xsl:for-each select='row'><tr valign='middle' height='20px'><td class='fly-select-item' onclick=\"lex.$(this).removeClass('lex-select-item-over');lex.widgets.$('" + this.id + "').select('{name}');\" onmouseover=\"lex.$(this).addClass('lex-select-item-over')\" onmouseout=\"lex.$(this).removeClass('lex-select-item-over')\"><xsl:value-of select='name'/></td></tr></xsl:for-each></table></xsl:template></xsl:stylesheet>");
		var mod = lex.createModel([{name:'8:00',value:'8:00'},{name:'8:30',value:'8:30'},{name:'9:00',value:'9:00'},{name:'9:30',value:'9:30'},{name:'10:00',value:'10:00'},{name:'10:30',value:'10:30'},{name:'11:00',value:'11:00'},{name:'11:30',value:'11:30'},{name:'12:00',value:'12:00'},{name:'12:30',value:'12:30'},{name:'13:00',value:'13:00'},{name:'13:30',value:'13:30'},{name:'14:00',value:'14:00'},{name:'14:30',value:'14:30'},{name:'15:00',value:'15:00'},{name:'15:30',value:'15:30'},{name:'16:00',value:'16:00'},{name:'16:30',value:'16:30'},{name:'17:00',value:'17:00'},{name:'17:30',value:'17:30'},{name:'18:00',value:'18:00'}]);
		pp.update(tmp.transform(lex.createDocument("<?xml version='1.0' encoding='utf-8'?>" + lex.xml(mod.getRows()))));
		pp.setHeight(120);
	},
	select: function(v){
		lex.$(this._did).setValue(v).fire('change');
		this.untrigger();
	}
});

//TODO
X.DataRender = X.create(X.Base,false,{
	onRender: function(rid){
		if( lex.isFunction(this._render) )
		{
			rid || ( rid = '' );
			var es = lex.$$('div[id^=' + this.id + rid + ']'),h;
			for(var i=0,len=es.length;i<len;i++)
			{
				h = this._render.apply(null,[i]);
				if( lex.isString(h) )
					es[i].update(h);
			}
		}
	}
});

//view
var _ix = function(rid){
	if( lex.isBlank(rid) ) return 0;
	if( lex.isNumber(rid) ) return rid;
	if( lex.isString(rid) )
	{
		var str = rid.replace(/(^_+)|(_+$)/g,'');
		if( /[0-9]+/.test(str) )
			return parseInt(str);
	}
	return 0;
};

X.View = X.create(X.Base,false,{
	init: function(id,name){
		this.$super(id,name);
		this.items = {};
		this.views = {};
		this.renders = [];
		this.afterModelReload = (function(){ var wg = this.getWidget(); wg._setData(lex.clone(this._mod.getRows())); wg.render(); }).bind(this);
	},
	getXSL: function(){
		if( !this.xsl )
		{
			var ss = [],ele = lex.$(this.id + '_xsl');
			if( !ele ) throw lex.format("View {0} xsl div not found.",this.id);
			ss.push(ele.value);
			for( var k in this.views ) ss.push(this.views[k].getXSL()); // merge xsl.
			this.xsl = ss.join('');
		}
		return this.xsl;
	},
	getModel: function(){ return this._mod; },
	setModel: function(mod){
		if( this._mod ) mod.un('load',this.afterModelReload);
		if( mod )
		{
			mod.on('load',this.afterModelReload);
			this.getWidget()._setData(lex.clone(mod.getRows()));
		}
		this._mod = mod;
	},
	binding: function(){
		if( arguments.length == 0 ) return;
		if( lex.isString(arguments[0]) )
		{
			var k = arguments[0],e = arguments[1];
			if( e ){ if( e instanceof X.View ) this.views[k] = e; else this.items[k] = e; e.view = this; }
		}
		else
		{
			var e = arguments[0];
			this.renders.push(e);
			e.view = this;
		}
	}
});

X.FormModel = lex.create({
	init: function(){

	}
});

_ms = {
	render: function(){
		var row = this.row,el = lex.$(this.id + "_body"),tmp = this._group.getTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(row));
		if( el && tmp && dom )
		{
			el.update(tmp.transform(dom,{pid:this.rid}));
			var v,its = this._group.items;
			for(var k in its)
			{
				v = its[k].getWidget(this.rid).getValue();
				if( !lex.isBlank(v) ) row[k] = v;
			}
			this._group.fire('render');
		}
	},
	reset: function(){ this._setData(this.rows); this.render(); },
	getRow: function(){ return this.row; },
	setRow: function(r){ if( r ){ var v; for(var k in  r) if( lex.isString(k) && !lex.isFunction(v = r[k]) ) this.row.set(k,v); } },
	getIndex: function(){ return this.index || ( this.index = 1 ); },
	setIndex: function(ix){
		var thiz = this._group;
		this.index = ix;
		this.row = lex.mixin(lex.clone(this.rows[ix-1]||{}),{$rid: this.rid,get: function(n){ return this[n]; },set: function(n,v){ this[n] = v; if( thiz.items[n] ){ var w = thiz.items[n].getWidget(this.$rid); if( w && w.setValue ) w.setValue(v); } }});
		for(var k in thiz.views) thiz.views[k].getWidget(this.rid)._setData(this.row[k] || ( this.row[k] = [] ));
	},

	_setValue: function(ix,k,v){ this.row[k] = v; },
	_setData: function(rows){
		this.rows = rows || [];
		this.setIndex( this.rows.length == 0 ? 1 : Math.min(this.rows.length,this.getIndex()) );
	}
};
X.Form = X.create(X.View,_ms,{
	onRender: function(){
		for(var k in this.items) this.items[k].fire('render');
		for(var k in this.views) this.views[k].fire('render');
		for(var i=0;i<this.renders.length;i++) this.renders[i].fire('render');
	},
	getTemplate: function(){
		if( !this._tmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/>"];
			xsl.push("<xsl:template match='/row'><xsl:call-template name='" + this.id + "_row'><xsl:with-param name='pid' select='$pid'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._tmp = lex.createTemplate(xsl.join(''));
		}
		return this._tmp;
	}
});

_ms = {
	render: function(){
		var el = this._el(),tmp = this._group.getTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(this.rows));
		if( el && tmp && dom )
		{
			el.update(tmp.transform(dom,{pid:this.rid}));
			if( this.orderby )
				lex.$(this.id + 'h' + this.orderby.index).addClass( this.orderby.type == 'ASC' ? 'lex-sort-asc' : 'lex-sort-desc' );
			this._group.fire('render',this);
		}
	},
	getRows: function(){ return this.rows; },
	getRowCount: function(){ return this.rows.length; },
	getRow: function(ix){
		ix = _ix(ix);
		return this.rows[this.indexs[ix]];
	},
	setRow: function(ix,nrow){
		ix = _ix(ix);
		var row = this.getRow(ix),val;
		if( !row ) return;
		for(var k in  nrow) if( lex.isString(k) && !lex.isFunction(val = nrow[k]) ) row.set(k,val);
	},

	addRow: function(row){ this.addRows([row]); },
	addRows: function(rows){
		for(var i=0,len=rows.length;i<len;i++) this._addRow(rows[i]);
		this._group.fire('render');
	},
	removeRow: function(ix){ this.removeRows([ix]); },
	removeRows: function(ixs){ for(var i=0;i<ixs.length;i++) this._removeRow(ixs[i]); },
	rowed: function(ix,row){
		var thiz = this._group,rid = this.rid + '_' + ix;
		lex.mixin(row,{$rid:rid,$index:ix,get: function(n){ return this[n]; },set: function(n,v){ this[n] = v; if( thiz.items[n] ){ var w = thiz.items[n].getWidget(this.$rid); if( w && w.setValue ) w.setValue(v); } }});
		for(var k in thiz.views) thiz.views[k].getWidget(rid)._setData(row[k] || ( row[k] = [] ));
	},

	_addRow: function(row){
		row = lex.mixin({},row);
		var rt = this._group.getRowTemplate(),ix = this.indexs.length;
		var tb = lex.$(this.id + '_tb'),dom = lex.createDocument(lex.xmlHeader + lex.xml(row));
		if( tb && rt && dom )
			lex.util.insertLast(tb,rt.transform(dom,{pid:this.rid,index:ix}));
		this.indexs.push(this.rows.length); // set current index.
		this.rowed(ix,row);
		this.rows.push(row);
		this._group.fire("rowAdd",this.rid + '_' + ix,ix);
	},
	_removeRow: function(ix){
		ix = _ix(ix);
		var ele = lex.$(this.id + '_r' + ix);
		if( ele )
		{
			ele.remove(); // remove tr.
			var tmp = this.indexs[ix];
			this.rows.remove(tmp);
			this.indexs[ix] = -1;
			for(var i=ix+1,len=this.indexs.length;i<len;i++) if( this.indexs[i] > tmp ) this.indexs[i]--;
			this._group.fire("rowRemove",this.rid + '_' + ix,ix); // fire rowRemove.
		}
	},

	_setValue: function(ix,prop,value){
		ix = this.indexs[ix];
		if( ix >= 0 && ix < this.rows.length )
			this.rows[ix][prop] = value;
	},
	_setData: function(rows){ // set view data.
		var row;
		this.indexs = [];
		this.rows = rows || ( rows = [] );
		for(var i=0,len=rows.length;i<len;i++) // for each rows.
		{
			this.rowed(i,rows[i]);
			this.indexs.push(i);
		}
	},

	select: function(ix,se){
		var e;
		if( this._group.single )
		{
			if( lex.isNumber(this.selected) )
			{
				e = lex.$(this.id + '_se' + this.selected);
				if( e ) e.checked = false;
				e = lex.$(this.id + '_r' + this.selected);
				if( e ) e.removeClass('lex-grid-row-select');
			}
			e = lex.$(this.id + '_se' + ix);
			if( e ) e.checked = se;
			e = lex.$(this.id + '_r' + ix);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
			this.selected = se ? ix : false;
		}
		else
		{
			e = lex.$(this.id + '_se' + ix);
			if( e ) e.checked = se;
			e = lex.$(this.id + '_r' + ix);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
		}
	},
	selectAll: function(se){
		var e;
		for(var i=0,len=this.indexs.length;i<len;i++)
		{
			if( this.indexs[i] < 0 ) continue;
			e = lex.$(this.id + '_r' + i);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
			e = lex.$(this.id + '_se' + i);
			if( e ) e.checked = se;
		}
	},
	getSelected: function(){
		if( lex.isNumber(this.selected) ) return [this.selected];
		var ret = [],e;
		for(var i=0,len=this.indexs.length;i<len;i++)
		{
			if( this.indexs[i] < 0 ) continue;
			e = lex.$(this.id + '_se' + i);
			if( e && e.checked ) ret.push(i);
		}
		return ret;
	},
	ordering: function(p,ix){
		var m = this._group.getModel(),e = lex.$(this.id+'h'+ix);
		if( m && e )
		{
			if( e.hasClass('lex-sort-asc') )
			{
				this.orderby = {index:ix,type:'DESC'};
				p += " DESC";
			}
			else
			{
				this.orderby = {index:ix,type:'ASC'};
				p += " ASC";
			}
			m.ordering(p,true);
		}
	},

	setColumnTitle: function(ix,title){
		var ta = lex.$(this.id+'_ta');
		if( ix >= 0 && ta.rows && ta.rows[0] && ix < ta.rows[0].cells.length )
			ta.rows[0].cells[ix].innerHTML = title;
	},
	showColumn: function(ix){
		var ta = lex.$(this.id+'_ta');
		if( ix >= 0 && ta.rows && ta.rows[0] && ix < ta.rows[0].cells.length )
		{
			for(var i=0,len=ta.rows.length;i<len;i++)
				ta.rows[i].cells[ix].style.display = '';
		}
	},
	hideColumn: function(ix){
		var ta = lex.$(this.id+'_ta');
		if( ix >= 0 && ta.rows && ta.rows[0] && ix < ta.rows[0].cells.length )
		{
			for(var i=0,len=ta.rows.length;i<len;i++)
				ta.rows[i].cells[ix].style.display = 'none';
		}
	}
};
X.Grid = X.create(X.View,_ms,{
	init: function(id,name){
		this.$super(id,name);
	},
	onRender: function(wg){
		for(var k in this.items) this.items[k].fire('render');
		for(var k in this.views) this.views[k].fire('render');
		for(var i=0;i<this.renders.length;i++) this.renders[i].fire('render');
	},
	getTemplate: function(){
		if( !this._tmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/>"];
			xsl.push("<xsl:template match='/rows'><xsl:call-template name='" + this.id + "'><xsl:with-param name='rows' select='row'/><xsl:with-param name='pid' select='$pid'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._tmp = lex.createTemplate(xsl.join(''));
		}
		return this._tmp;
	},
	getRowTemplate: function(){
		if( !this._rtmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/><xsl:param name='index'/>"];
			xsl.push("<xsl:template match='/row'><xsl:call-template name='" + this.id + "_row'><xsl:with-param name='pid' select='$pid'/><xsl:with-param name='index' select='$index'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._rtmp = lex.createTemplate(xsl.join(''));
		}
		return this._rtmp;
	}
});

_ms = {
	render: function(){
		var el = this._el(),tmp = this._group.getTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(this.rows));
		if( el && tmp && dom )
		{
			el.update(tmp.transform(dom,{pid:this.rid}));
			if( this.orderby )
				lex.$(this.id + 'h' + this.orderby.index).addClass( this.orderby.type == 'ASC' ? 'lex-sort-asc' : 'lex-sort-desc' );
			this._group.fire('render',this);
		}
	},
	getRows: function(){ return this.rows; },
	getRowCount: function(){ return this.rows.length; },
	getRow: function(ix){
		ix = _ix(ix);
		return this.rows[this.indexs[ix]];
	},
	setRow: function(ix,nrow){
		ix = _ix(ix);
		var row = this.getRow(ix),val;
		if( !row ) return;
		for(var k in  nrow) if( lex.isString(k) && !lex.isFunction(val = nrow[k]) ) row.set(k,val);
	},

	addRow: function(row){ this.addRows([row]); },
	addRows: function(rows){
		for(var i=0,len=rows.length;i<len;i++) this._addRow(rows[i]);
		this._group.fire('render');
	},
	removeRow: function(ix){ this.removeRows([ix]); },
	removeRows: function(ixs){ for(var i=0;i<ixs.length;i++) this._removeRow(ixs[i]); },
	rowed: function(ix,row){
		var thiz = this._group,rid = this.rid + '_' + ix;
		lex.mixin(row,{$rid:rid,$index:ix,get: function(n){ return this[n]; },set: function(n,v){ this[n] = v; if( thiz.items[n] ){ var w = thiz.items[n].getWidget(this.$rid); if( w && w.setValue ) w.setValue(v); } }});
		for(var k in thiz.views) thiz.views[k].getWidget(rid)._setData(row[k] || ( row[k] = [] ));
	},

	_addRow: function(row){
		row = lex.mixin({},row);
		var rt = this._group.getRowTemplate(),ix = this.indexs.length;
		var tb = lex.$(this.id).lastChild.firstChild,dom = lex.createDocument(lex.xmlHeader + lex.xml(row));
		if( tb && rt && dom )
			lex.util.insertLast(tb,rt.transform(dom,{pid:this.rid,index:ix}));
		this.indexs.push(this.rows.length); // set current index.
		this.rowed(ix,row);
		this.rows.push(row);
		this._group.fire("rowAdd",this.rid + '_' + ix,ix);
	},
	_removeRow: function(ix){
		ix = _ix(ix);
		var ele = lex.$(this.id + '_r' + ix);
		if( ele )
		{
			ele.remove(); // remove tr.
			var tmp = this.indexs[ix];
			this.rows.remove(tmp);
			this.indexs[ix] = -1;
			for(var i=ix+1,len=this.indexs.length;i<len;i++) if( this.indexs[i] > tmp ) this.indexs[i]--;
			this._group.fire("rowRemove",this.rid + '_' + ix,ix); // fire rowRemove.
		}
	},

	_setValue: function(ix,prop,value){
		ix = this.indexs[ix];
		if( ix >= 0 && ix < this.rows.length )
			this.rows[ix][prop] = value;
	},
	_setData: function(rows){ // set view data.
		var row;
		this.indexs = [];
		this.rows = rows || ( rows = [] );
		for(var i=0,len=rows.length;i<len;i++) // for each rows.
		{
			this.rowed(i,rows[i]);
			this.indexs.push(i);
		}
	},

	select: function(ix,se){
		var e;
		if( this._group.single )
		{
			if( lex.isNumber(this.selected) )
			{
				e = lex.$(this.id + '_se' + this.selected);
				if( e ) e.checked = false;
				e = lex.$(this.id + '_r' + this.selected);
				if( e ) e.removeClass('lex-grid-row-select');
			}
			e = lex.$(this.id + '_se' + ix);
			if( e ) e.checked = se;
			e = lex.$(this.id + '_r' + ix);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
			this.selected = se ? ix : false;
		}
		else
		{
			e = lex.$(this.id + '_se' + ix);
			if( e ) e.checked = se;
			e = lex.$(this.id + '_r' + ix);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
		}
	},
	selectAll: function(se){
		var e;
		for(var i=0,len=this.indexs.length;i<len;i++)
		{
			if( this.indexs[i] < 0 ) continue;
			e = lex.$(this.id + '_r' + i);
			if( e ){ if( se ) e.addClass('lex-grid-row-select'); else e.removeClass('lex-grid-row-select'); }
			e = lex.$(this.id + '_se' + i);
			if( e ) e.checked = se;
		}
	},
	getSelected: function(){
		if( lex.isNumber(this.selected) ) return [this.selected];
		var ret = [],e;
		for(var i=0,len=this.indexs.length;i<len;i++)
		{
			if( this.indexs[i] < 0 ) continue;
			e = lex.$(this.id + '_se' + i);
			if( e && e.checked ) ret.push(i);
		}
		return ret;
	},
	ordering: function(p,ix){
		var m = this._group.getModel(),e = lex.$(this.id+'h'+ix);
		if( m && e )
		{
			if( e.hasClass('lex-sort-asc') )
			{
				this.orderby = {index:ix,type:'DESC'};
				p += " DESC";
			}
			else
			{
				this.orderby = {index:ix,type:'ASC'};
				p += " ASC";
			}
			m.ordering(p,true);
		}
	},
	_adjustWidth: function(){
		var e = this._el(),w = e.clientWidth,h = e.clientHeight;
		if( w == 0 ) return;
		var hd = e.$$('div.lex-grid-hd')[0].firstChild,bd = e.$$('div.lex-grid-bd')[0].firstChild,ht = hd.firstChild;
		var hs = ht.offsetWidth - w,vs = bd.offsetHeight + hd.offsetHeight - h;
		if( hs > 0 )
		{
			hd.style.width = ( w - 18 ) + 'px';
			bd.style.width = w + 'px';
			bd.style.height = ( h - hd.offsetHeight - 2 ) + 'px';
		}
		else
		{
			if( vs > 0 )
			{
				hd.style.width = ( w - 18 ) + 'px';
				bd.style.height = ( h - hd.offsetHeight - 2 ) + 'px';
			}
			else
			{
				hd.style.width = w + 'px';
				bd.style.width = w + 'px';
				bd.style.height = 'auto';
			}
		}
		var tr = ht.rows[0],cols=tr.cells.length,ws = [],row;
		for(var i=0;i<cols;i++)
			ws.push({left:tr.cells[i].offsetLeft + 'px',width:tr.cells[i].offsetWidth + 'px'});
		w = ht.offsetWidth + 'px';
		for(var i=0,len=this.rows.length;i<len;i++)
		{
			row = lex.$(this.id + '_r' + this.rows[i].$index);
			if( row && ( row = row.firstChild ) && ( tr = row.rows[0] ) )
			{
				row.style.width = w;
				for(var j=0;j<cols;j++) tr.cells[j].style.width = ws[j].width;
			}
	    }
	}
};
X.NGrid = X.create(X.View,_ms,{
	init: function(id,name){
		this.$super(id,name);
		lex.onResize((function(){ var ws = this.getWidgets(); for(var k in ws){ ws[k]._adjustWidth(); } }).bind(this));
	},
	onRender: function(wg){
		( wg || this.getWidget() )._adjustWidth();
		for(var k in this.items) this.items[k].fire('render');
		for(var k in this.views) this.views[k].fire('render');
		for(var i=0;i<this.renders.length;i++) this.renders[i].fire('render');
	},
	getTemplate: function(){
		if( !this._tmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/>"];
			xsl.push("<xsl:template match='/rows'><xsl:call-template name='" + this.id + "'><xsl:with-param name='rows' select='row'/><xsl:with-param name='pid' select='$pid'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._tmp = lex.createTemplate(xsl.join(''));
		}
		return this._tmp;
	},
	getRowTemplate: function(){
		if( !this._rtmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/><xsl:param name='index'/>"];
			xsl.push("<xsl:template match='/row'><xsl:call-template name='" + this.id + "_row'><xsl:with-param name='pid' select='$pid'/><xsl:with-param name='index' select='$index'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._rtmp = lex.createTemplate(xsl.join(''));
		}
		return this._rtmp;
	}
});

_ms = {
	render: function(){
		var tmp = this._group.getTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(this.rows)),el = this._el();
		if( tmp && dom && el )
		{
			el.update(tmp.transform(dom,{pid:this.rid}));
			this._group.fire('render');
		}
	},
	getRows: function(){ return this.rows; },
	getRowCount: function(){ return this.rows.length; },
	getRow: function(ix){ return this.rows[_ix(ix)]; },
	setRow: function(ix,nrow){
		var row = this.getRow(ix),val;
		if( !row ) return;
		for(var k in  nrow) if( lex.isString(k) && !lex.isFunction(val = nrow[k]) ) row.set(k,val);
	},
	addRow: function(row){ this.addRows([row]); },
	addRows: function(rows){
		for(var i=0,len=rows.length;i<len;i++)
			this._addRow(rows[i]);
		this.render();
	},
	removeRow: function(ix){ this.removeRows([ix]); },
	removeRows: function(ixs){
		if( !ixs || ( lex.isArray(ixs) == false ) || ( ixs.length ==  0 ) ) return;
		ixs.sort();
		for(var i=ixs.length-1;i>=0;i--)
			this._removeRow(ixs[i]);
		this.render();
	},
	rowed: function(ix,row){
		var thiz = this._group,rid = this.rid + '_' + ix;
		lex.mixin(row,{$rid:rid,$index:ix,get: function(n){ return this[n]; },set: function(n,v){ this[n] = v; if( thiz.items[n] ){ var w = thiz.items[n].getWidget(this.$rid); if( w && w.setValue ) w.setValue(v); } }});
		for(var k in thiz.views) thiz.views[k].getWidget(rid)._setData(row[k] || ( row[k] = [] ));
	},

	_addRow: function(row){
		var ix = this.rows.length;
		row = lex.mixin({},row);
		this.rowed(ix,row);
		this.rows.push(row);
	},
	_removeRow: function(ix){
		ix = _ix(ix);
		if( ix < 0 || ix >= this.rows.length ) return;
		this.rows.remove(ix);
	},
	_setValue: function(ix,prop,value){ this.rows[ix][prop] = value; },
	_setData: function(rs){
		this.rows = ( rs || ( rs = [] ) );
		for(var i=0,len=rs.length;i<len;i++) this.rowed(i,rs[i]);
	}
};
X.List = X.create(X.View,_ms,{
	onRender: function(){
		for(var k in this.items) this.items[k].fire('render');
		for(var k in this.views) this.views[k].fire('render');
		for(var i=0;i<this.renders.length;i++) this.renders[i].fire('render');
	},
	getTemplate: function(){
		if( !this._tmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/>"];
			xsl.push("<xsl:template match='/rows'><xsl:call-template name='" + this.id + "'><xsl:with-param name='rows' select='row'/><xsl:with-param name='pid' select='$pid'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._tmp = lex.createTemplate(xsl.join(''));
		}
		return this._tmp;
	}
});

_ms = {
	render: function(){
		var tmp = this._group.getTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(this.rows)),el = this._el();
		if( tmp && dom && el )
		{
			el.update(tmp.transform(dom,{pid:this.rid}));
			this._group.fire('render');
		}
	},
	toggleNode: function(p){ //path,code
		el = lex.$(this.id + p + '_tg');
		if( el.hasClass('lex-tree-trigger-open') )
		{
			el.removeClass('lex-tree-trigger-open');
			el = lex.$(this.id + p + '_ct');
			if( el ) el.hide();
		}
		else
		{
			el.addClass('lex-tree-trigger-open');
			el = lex.$(this.id + p + '_ct');
			if( el )
			{
				var rs = this._group.getModel().getRows(),tmp = this._group.getRowTemplate(),dom = lex.createDocument(lex.xmlHeader + lex.xml(rs));
				if( tmp && dom )
				{
					el.update(tmp.transform(dom,{pid:this.rid,pp:p}));
				}
				el.show();
				this._adjustWidth(p);
			}
		}
	},
	getRow: function(p){ p = ( lex.isUndefined(p) ? '-0' : lex.isNumber(p) ? '-' + p : p ); return this.rows[p]; },
	getRows: function(p){
		//TODO get rows and put into map.
	},
	rowed: function(ix,row){
		var thiz = this._group,rid = this.rid + '_' + ix;
		lex.mixin(row,{$rid:rid,get: function(n){ return this[n]; },set: function(n,v){ this[n] = v; if( thiz.items[n] ){ var w = thiz.items[n].getWidget(this.$rid); if( w && w.setValue ) w.setValue(v); } }});
		for(var k in thiz.views) thiz.views[k].getWidget(rid)._setData(row[k] || ( row[k] = [] ));
	},

	_setValue: function(ix,prop,value){ this.rows[ix][prop] = value; },
	_setData: function(rs){
		this.rows = ( rs || ( rs = [] ) );
		for(var i=0,len=rs.length;i<len;i++) this.rowed(i,rs[i]);
	},

	_adjustWidth: function(path){
		path || ( path = '' );
		var e = this._el();
		var hd = e.$$('div.lex-tree-hd')[0].firstChild,bd = e.$$('div.lex-tree-bd')[0].firstChild,ht = hd.firstChild;
		var w = e.clientWidth,h = e.clientHeight,hs = ht.offsetWidth - w,vs = bd.offsetHeight + hd.offsetHeight - h;
		if( hs > 0 )
		{
			bd.style.width = w + 'px';
			bd.style.height = ( h - hd.offsetHeight - 2 ) + 'px';
			hd.style.width = ( w - 18 ) + 'px';
		}
		else
		{
			if( vs > 0 )
			{
				hd.style.width = ( w - 18 ) + 'px';
				bd.style.height = ( h - hd.offsetHeight - 2 ) + 'px';
			}
			else
			{
				hd.style.width = w + 'px';
				bd.style.width = w + 'px';
				bd.style.height = ( h - hd.offsetHeight ) + 'px';
			}
		}
		var tr = ht.rows[0],cols=tr.cells.length,ws = [],row;
		for(var i=0;i<cols;i++)
			ws.push({left:tr.cells[i].offsetLeft + 'px',width:tr.cells[i].offsetWidth + 'px'});
		w = ht.offsetWidth + 'px';
		for(var i=0;true;i++)
		{
			row = lex.$(this.id + path + '_r' + i);
			if( !row || !( row = row.firstChild ) || !( tr = row.rows[0] )) break;
			row.style.width = w;
			for(var j=0;j<cols;j++) tr.cells[j].style.width = ws[j].width;
	    }
	}
};
X.Tree = X.create(X.View,_ms,{
	onRender: function(wg){
		( wg || this.getWidget() )._adjustWidth();
		for(var k in this.items) this.items[k].fire('render');
		for(var k in this.views) this.views[k].fire('render');
		for(var i=0;i<this.renders.length;i++) this.renders[i].fire('render');
	},
	getTemplate: function(){
		if( !this._tmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/>"];
			xsl.push("<xsl:template match='/rows'><xsl:call-template name='" + this.id + "'><xsl:with-param name='rows' select='row'/><xsl:with-param name='pid' select='$pid'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._tmp = lex.createTemplate(xsl.join(''));
		}
		return this._tmp;
	},
	getRowTemplate: function(){
		if( !this._rtmp )
		{
			var xsl = [lex.xslHeader,"<xsl:param name='pid'/><xsl:param name='pp'/>"];
			xsl.push("<xsl:template match='/rows'><xsl:call-template name='" + this.id + "_rows'><xsl:with-param name='rows' select='row'/><xsl:with-param name='pid' select='$pid'/><xsl:with-param name='pp' select='$pp'/></xsl:call-template></xsl:template>");
			xsl.push(this.getXSL());
			xsl.push("<xsl:template match='*'></xsl:template></xsl:stylesheet>");
			this._rtmp = lex.createTemplate(xsl.join(''));
		}
		return this._rtmp;
	}
});

})();

/*--------------------------------------------------------------------------*/
// deprecated.
lex.declare('',['lex_extend',lex.mixin]);
}